<?php

namespace common\service;

use common\exception\LogicException;
use common\model\CosMediaModel;
use common\model\EntityModel;
use common\model\PlanModel;
use common\model\PlanTaskRelationModel;
use common\model\ProjectMemberModel;
use common\model\StatusModel;
use common\model\StepModel;
use common\model\TaskClockModel;
use common\model\TaskMemberModel;
use common\model\TaskMemberRelationModel;
use common\model\TaskModel;
use common\model\TaskRelationModel;
use common\model\TaskRelationTagModel;
use common\model\TaskWorkOrderModel;
use common\model\TaskWorkOrderTaskListModel;
use common\model\TaskWorkOrderUserModel;
use common\model\TemplateTodoFileModel;
use common\model\UserModel;
use common\model\VersionModel;
use Exception;
use malkusch\lock\mutex\PHPRedisMutex;
use support\bootstrap\Redis;
use support\ErrorCode;
use support\SingletonTrait;
use think\Hook;
use Throwable;
use Webman\Stomp\Client;

class TaskMemberService
{
    // 单例工具
    use SingletonTrait;

    /**
     * @var object|\think\Model|\think\model\RelationModel
     */
    private $taskMemberModel;
    private $TaskMemberRelationModel;
    private $taskRelationTag;
    private $taskRelation;
    private $planModel;

    public function __construct()
    {
        $this->taskRelation = model(TaskRelationModel::class);
        $this->taskMemberModel = model(TaskMemberModel::class);
        $this->TaskMemberRelationModel = model(TaskMemberRelationModel::class);
        $this->taskRelationTag = model(TaskRelationTagModel::class);
        $this->planModel = model(PlanModel::class);
    }

    /**
     * 创建待办任务
     * @param $data
     * @param $userId
     * @param $tenantId
     * @return array
     * @throws Throwable
     * @throws \think\Exception
     */
    public function create($data, $userId, $tenantId)
    {
        //兼容以前的时间传递方式
        if (!empty($data['task']['plan_start_time']) && is_numeric($data['task']['plan_start_time'])) {
            $data['task']['plan_start_time'] = date('Y-m-d H:i:s', $data['task']['plan_start_time']);
        }
        if (!empty($data['task']['plan_end_time']) && is_numeric($data['task']['plan_end_time'])) {
            $data['task']['plan_end_time'] = date('Y-m-d H:i:s', $data['task']['plan_end_time']);
        }

        $receives = array_merge($data['executor'] ?? [], $data['partner'] ?? []);
        $model = model(TaskMemberModel::class);
        // 任务表中保存一条新的数据
        $commonService = CommonService::instance("task");
        $data['task']['created_by'] = $userId;
        $commonService->setCurrentModuleCode("task");
        if (empty($data['task']['task_status'])) {
            $statusService = StatusService::getInstance();
            $taskDefaultStatus = $statusService->getTaskDefaultStatus();
            if (!empty($taskDefaultStatus)) {
                $data['task']['task_status'] = $taskDefaultStatus['id'];
            }
        }
        $data['task']['entity_module_id'] = module_by_code('todo')['id'];
        $data['task']['tenant_id'] = $tenantId;
        $data['task']['task_clock_time'] = [];
        if (isset($data['task']['work_order_id'])) {
            $data['task']['task_work_order_id'] = $data['task']['work_order_id'];
        }
        if (isset($data['task']['notify_config']) && !empty($data['task']['plan_end_time'])) {
            $data['task']['task_notify_config'] = $data['task']['notify_config'];
            foreach ($data['task']['notify_config'] as $notify_config) {
                if ($notify_config['type'] == 'timestamp') {
                    $data['task']['task_clock_time'][] = $notify_config['value'];
                }
                if ($notify_config['type'] == 'code') {
                    $notify_config = explode('end_', $notify_config['value']);
                    $data['task']['task_clock_time'][] = strtotime("-{$notify_config[1]} minute", strtotime($data['task']['plan_end_time']));
                }
            }
        }
        $data['task']['code'] = '';
        $mediaService = MediaService::getInstance();

        // 处理子待办任务数据
        if (!empty($data['is_sub_todo']) && !empty($data['main_todo_id'])) {
            $data['task']['is_sub_todo'] = true; // 是否子待办任务
            $data['task']['parent_todo_task_id'] = $data['main_todo_id']; // 父待办任务id
        }

        // 处理模板待办任务数据
        if (!empty($data['task']['template_todo_id'])) {
            // 查询模板数据
            $templateTodoData = TemplateTodoService::getInstance()->getOne($data['task']['template_todo_id']);
            if (!empty($templateTodoData)) {
                if (!empty($templateTodoData['stage_id']) && !empty($data['template_todo_parent_task_id'])) {
                    $data['task']['task_stage_id'] = $templateTodoData['stage_id'];
                }
                $data['task']['template_todo_info'] = $templateTodoData;
            }
            // 发起人同步执行人(executor)
            $starterListToExecutor = [];
            foreach ($data['starter_list'] ?? [] as $starterItem) {
                foreach ($starterItem['user_list'] ?? [] as $starterUserId) {
                    if (in_array($starterUserId['user_id'] ?? 0, $starterListToExecutor)) {
                        continue;
                    }
                    $starterListToExecutor[] = $starterUserId['user_id'];
                }
            }
            if (!empty($starterListToExecutor)) {
                $data['executor'] = $starterListToExecutor;
            }
        }
        // 所有代办任务类型的任务 原计划交付时间 = 计划交付时间 = 计划完成时间
        if (empty($data['task']['plan_delivery_time'])) {
            if (is_numeric($data['task']['plan_end_time'])) {
                $data['task']['plan_delivery_time'] = $data['task']['plan_end_time'];
            } else {
                $data['task']['plan_delivery_time'] = strtotime($data['task']['plan_end_time']);
            }
        }

        $executorUserIdList = [];// 发起人+执行人
        foreach (['starter_list', 'executor_list', 'partner_list'] as $dk) {
            foreach ($data['task'][$dk] ?? [] as $memberItem) {
                $executorUserIdList[$memberItem['user_id']] = $memberItem['user_id'];
            }
        }

        $arr = []; // 待办成员
        $model->startTrans();
        try {
            $data = $mediaService->handleMediaItemUpload($data, 'task', model(TaskModel::class));
            $task = $commonService->create($data['task']);
            if ($data['task']['step_type'] == 'work_order_to_do') {
                $workOrderJoinTodo = [];
                $workOrderJoinTodo['work_order_id'] = $data['task']['work_order_id'];
                $workOrderJoinTodo['task_id'] = $task['id'];
                $workOrderJoinTaskModel = model(TaskWorkOrderTaskListModel::class);
                $resData = $workOrderJoinTaskModel->addItem($workOrderJoinTodo);
                if (!$resData) {
                    $errorCode = $workOrderJoinTaskModel->getErrorCode();
                    throw_strack_exception($workOrderJoinTaskModel->getError(), $errorCode);
                }
                // 绑定工单代办关联关系
                $workOrderIdTaskData = model(TaskWorkOrderModel::class)->where(['id' => $workOrderJoinTodo['work_order_id']])->field('id,number,task_id,step_category_id')->find();
                if (!empty($workOrderIdTaskData['task_id'])) {
                    $taskRelationProjectId = $task['project_id'] ?? 0;
                    $taskRelationData = [
                        'target_task_id' => $task['id'],
                        'source_task_id' => $workOrderIdTaskData['task_id'],
                        'relation_type' => TaskModel::STEP_TYPE_WORK_ORDER_TO_DO,
                        'source_step_category_id' => $workOrderIdTaskData['step_category_id'],
                        'target_step_category_id' => 0
                    ];
                    $requestRelation = TaskRelationService::getInstance()->addProjectTaskRelationData($taskRelationProjectId, $taskRelationData);
                    if (!$requestRelation) {
                        throw new LogicException('bind sub todo task fail', ErrorCode::BIND_DISMANTLE_RELATION_TASK_FAIL);
                    }
                }
            } else if ($data['task']['step_type'] == TaskModel::STEP_TYPE_ENTITY_TO_DO && !empty($data['task']['entity_id'])) {
                $entityQueryFields = [
                    'id',
                    'project_id',
                ];
                $designEntity = model(EntityModel::class)
                    ->alias('design')
                    ->field(transform_custom_fields($entityQueryFields, 'design'))
                    ->where(['id' => $data['task']['entity_id']])
                    ->find();
                if (empty($designEntity)) {
                    throw new LogicException('Entity not found', ErrorCode::ENTITY_NOT_FOUND);
                }
                $designTaskIdList = model(TaskModel::class)
                    ->where([
                        'project_id' => $designEntity['project_id'],
                        'entity_module_id' => module_by_code('todo')['id'],
                        'entity_id' => $designEntity['id'],
                        'step_type' => TaskModel::STEP_TYPE_ENTITY_TO_DO,
                    ])
                    ->field('id')
                    ->column('id');

                $entityUpdateData = [
                    'id' => $designEntity['id'],
                    'design_task' => implode(',', $designTaskIdList),
                ];
                $entityCommonService = CommonService::instance('entity');
                $entityCommonService->setCurrentModuleCode('design');
                $entityCommonService->update($entityUpdateData, 'design', false);
            }

            // 组织模板待办成员,相同环节,角色,执行人,发起人,部门,合并到一行
            if (!empty($executorUserIdList)) {
                $executorUserIdMap = $this->getSaasUserId($executorUserIdList, true);
                foreach (['starter_list', 'executor_list', 'partner_list'] as $dk) {
                    foreach ($data['task'][$dk] ?? [] as $memberItem) {
                        $currentUserId = $executorUserIdMap[$memberItem['user_id']] ?? 0;
                        if ($currentUserId <= 0) {
                            continue;
                        }
                        if ($dk === 'executor_list') {
                            $arr = $this->getMember($arr, $currentUserId, $currentUserId, $task['id'], $data['task']['task_status'], $currentUserId);
                        }
                        if ($dk === 'starter_list') {
                            $arr = $this->getMember($arr, 0, 0, $task['id'], $data['task']['task_status'], $currentUserId, $currentUserId);
                        }
                        if ($dk === 'partner_list') {
                            $arr = $this->getMember($arr, 0, $currentUserId, $task['id'], $data['task']['task_status'], $currentUserId, 0);
                        }
                    }
                }
            }

            // 提醒时间存储
            if (!empty($data['task']['task_clock_time'])) {
                $clock = [];
                $taskClock = model(TaskClockModel::class);
                foreach ($data['task']['task_clock_time'] as $k => $v) {
                    $clock[$k]['task_id'] = $task['id'];
                    $clock[$k]['time'] = $v;
                    $clock[$k]['created_by'] = $userId;
                    $clock[$k]['created'] = time();
                    $clock[$k]['type'] = "to_do";
                }
                $taskClock->addAll($clock);
                $clock = array_column($clock, 'time');
                $this->notifyTaskMemberUser($task, array_keys($arr), $clock);
            }

            //标签关联
            if (!empty($data['relate_tag'])) {
                $this->toDoTaskRelateTag($task, $data['relate_tag']);
            }
            // 将数组重新排序
            $res = $model->addAll(array_column($arr, null));

            // 子待办
            if (!empty($data['is_sub_todo']) && !empty($data['main_todo_id'])) {
                $taskRelationData = [
                    'source_task_id' => $data['main_todo_id'],
                    'target_task_id' => $task['id'],
                    'relation_type' => TaskRelationModel::RELATION_TYPE_SUB_TODO
                ];
                // 绑定关联关系
                $requestRelation = model(TaskRelationModel::class)
                    ->setSuffix(sprintf('_project_%d', $task['project_id'] ?? 0))
                    ->addItem($taskRelationData);
                if (!$requestRelation) {
                    throw new LogicException('bind sub todo task fail', ErrorCode::BIND_DISMANTLE_RELATION_TASK_FAIL);
                }
            }

            if (!empty($data['task']['template_todo_id']) && !empty($task['template_todo_parent_task_id'])) {
                $taskRelationData = [
                    'source_task_id' => $task['template_todo_parent_task_id'],
                    'target_task_id' => $task['id'],
                    'relation_type' => TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO
                ];
                // 绑定关联关系
                $requestRelation = model(TaskRelationModel::class)
                    ->setSuffix(sprintf('_project_%d', $task['project_id']))
                    ->addItem($taskRelationData);
                if (!$requestRelation) {
                    throw new LogicException('bind template todo task fail', ErrorCode::BIND_DISMANTLE_RELATION_TASK_FAIL);
                }
            }

            $isCommit = $model->commit();
            if ($isCommit) {
                $receives = array_values($executorUserIdList);
                try {
                    if (!isset($task['task_status']) || $task['task_status'] <> 3) {
                        $this->notifyTaskMemberUser($task, array_keys($arr));
                        if (!empty($data['task']['work_order_id'])) {
                            $this->sendWorkOrderWaitMessage($data['task']['work_order_id'], $data['task']['name'], $receives);
                        }
                    }
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
            }
            return ["task_member" => $res, "task" => $task];
        } catch (Throwable $e) {
            $model->rollback();
            throw $e;
        }
    }


    /**
     * 发送工单待办消息
     * @param $taskId
     * @param $name
     * @param array $receives
     */
    public function sendWorkOrderWaitMessage($taskId, $name, array $receives = [])
    {
        if (empty($receives)) {
            return;
        }
        $taskWorkOrder = model(TaskWorkOrderModel::class)->field('name,chat_global_id')
            ->where(['id' => $taskId])->where("chat_global_id !=''")
            ->find();
        if (empty($taskWorkOrder)) {
            return;
        }
        $requestData = [
            "data" => [
                'receives' => $receives,
                'content_type' => 'create_work_order_wait',
                'global_id' => $taskWorkOrder['chat_global_id'],
                'content_extra_data' => ['work_order_name' => $name]
            ]
        ];
        teamones_request('teamones-im', 'message/push_work_order_chat_message', $requestData);
    }

    /**
     * 查询待办任务
     * @param $filter
     * @param $userId
     * @param $tenantId
     * @return array
     * @throws \think\Exception
     */
    public function select($filter, $userId, $tenantId)
    {
        $data = $filter['filter'];
        $data['task.tenant_id'] = $tenantId;
        $page = $filter['page'] ?? [];
        if (!isset($data['task_id'])) {
            $page = [1, C("default_page_total")];
        }
        $statusService = StatusService::getInstance();
        $taskStatus = $statusService->getList([], "*");
        if (isset($data['status_code'])) {
            $data = $this->getTaskMemberFilter($data, $taskStatus, $userId);//判断状态 进行查询语句的where
        }
        // 执行人是我的待办状态筛选
        if (isset($data['task_member_status_code'])) {
            $statusList = StatusService::getInstance()->getList(['code' => $data['task_member_status_code']], 'id');
            $data['task_member.status'] = ['IN', array_column($statusList, 'id')];
            $data[] = [
                'task_member.user_id' => $userId,
            ];
            unset($data['task_member_status_code']);
        }
        // 待办整体状态筛选
        if (isset($data['task_status_code'])) {
            $statusList = StatusService::getInstance()->getList(['code' => $data['task_status_code']], 'id');
            $data["task.json->>'$.task_status'"] = ['IN', array_column($statusList, 'id')];
            unset($data['task_status_code']);
        }
        if (isset($data['work_order_id'])) {
            $data[] = [
                "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_work_order_id'))" => $data['work_order_id']
            ];
            unset($data['work_order_id']);
        }

        $field = "task_member.*,task.entity_id,task.created_by,task.description,task.name,task.plan_end_time,project.id as project_id,project.name as project_name,JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_work_order_id')) AS work_order_id,JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status')) AS task_status";

        $taskMemberQuery = model(TaskMemberModel::class)
            ->field($field)
            ->where($data)
            ->join("task ON task_member.task_id = task.id")
            ->join("project ON task.project_id = project.id", 'LEFT')
            ->order("task.created DESC");
        if (!empty($page)) {
            $taskMemberQuery = $taskMemberQuery->page($page[0], $page[1]);
        }
        $res = $taskMemberQuery
            ->group('task_id,task.created')
            ->select();


        if (empty($res)) {
            return [];
        }
        // 获取同个任务下的其他参与者ID
        $taskIds = array_column($res, 'task_id');
        $taskMember = model(TaskMemberModel::class)->field('task_id,user_id,partner,starter,status')->where(['task_id' => ['in', implode(',', $taskIds)]])->select();
        $memberIds = array_column($taskMember, 'partner');
        $starterIds = array_column($taskMember, 'starter');
        $taskCreatedByIds = array_column($res, 'created_by');
        if (!empty($starterIds)) {
            $memberIds = array_merge($memberIds, $starterIds);
        }
        if (!empty($taskCreatedByIds)) {
            $memberIds = array_merge($memberIds, $taskCreatedByIds);
        }
        $member = model(UserModel::class)->field('id,name,union_id,avatar')->where(['id' => ['in', implode(',', $memberIds)]])->select();
        $memberMap = array_column($member, null, 'id');
        // 获取提醒时间
        $taskClockModel = model(TaskClockModel::class);
        $taskClockList = $taskClockModel->field('task_id,time')->where(['task_id' => ['IN', $taskIds], ['type' => 'to_do']])->select();
        $taskClockList = array_group_by($taskClockList, 'task_id');
        // 查询贴图任务
        $designTexStepTaskList = $entityNameList = [];
        $designIdList = array_column($res, 'entity_id', 'entity_id');
        unset($designIdList[0]);
        if (!empty($designIdList)) {
            $designTexStepTaskList = $this->getDesignTexStepTaskList($designIdList);
            $entityNameList = model(EntityModel::class)->where(['id' => ['IN', $designIdList]])->field('id,name')->select();
            $entityNameList = array_column($entityNameList, 'name', 'id');
        }

        // 获取状态ID
        foreach ($res as &$value) {
            $value['todo_time'] = $taskClockList[$value['task_id']] ?? [];
        }
        $taskStatusMap = array_column($taskStatus, 'code', 'id');
        return array_map(function ($item) use (&$taskStatusMap, &$taskMember, &$memberMap, $designTexStepTaskList, $entityNameList) {
            $item['member']['executor'] = [];
            $item['member']['partner'] = [];
            $item['member']['starter'] = [];
            $executorCount = 0;
            $partnerCount = 0;
            $starterCount = 0;
            foreach ($taskMember as $value) {
                if ($value['task_id'] == $item['task_id']) {
                    if (array_key_exists($value['user_id'], $memberMap)) {
                        $item['member']['executor'][$executorCount]['avatar'] = $memberMap[$value['user_id']]['avatar'] ?? null;
                        $item['member']['executor'][$executorCount]['name'] = $memberMap[$value['user_id']]['name'];
                        $item['member']['executor'][$executorCount]['status'] = $value['status'];
                        $item['member']['executor'][$executorCount]['user_id'] = $value['user_id'];
                        $item['member']['executor'][$executorCount]['union_id'] = $memberMap[$value['user_id']]['union_id'];
                        $executorCount++;
                    }
                    if (array_key_exists($value['partner'], $memberMap)) {
                        $item['member']['partner'][$partnerCount]['avatar'] = $memberMap[$value['partner']]['avatar'] ?? null;
                        $item['member']['partner'][$partnerCount]['name'] = $memberMap[$value['partner']]['name'];
                        $item['member']['partner'][$partnerCount]['status'] = $value['status'];
                        $item['member']['partner'][$partnerCount]['user_id'] = $value['partner'];
                        $item['member']['partner'][$partnerCount]['union_id'] = $memberMap[$value['partner']]['union_id'];
                        $partnerCount++;
                    }
                    if (array_key_exists($value['starter'], $memberMap)) {
                        $item['member']['starter'][$starterCount]['avatar'] = $memberMap[$value['starter']]['avatar'] ?? null;
                        $item['member']['starter'][$starterCount]['name'] = $memberMap[$value['starter']]['name'];
                        $item['member']['starter'][$starterCount]['status'] = $value['status'];
                        $item['member']['starter'][$starterCount]['user_id'] = $value['starter'];
                        $item['member']['starter'][$starterCount]['union_id'] = $memberMap[$value['starter']]['union_id'];
                        $starterCount++;
                    }
                }
            }
            $item['status'] = $taskStatusMap[$item['status']] ?? "not_started"; // 这是个人任务完成情况
            $item['task_status'] = $taskStatusMap[$item['task_status']] ?? "not_started"; // 这是整体任务完成情况
            $item['created_by_union_id'] = $memberMap[$item['created_by']]['union_id'];

            $item['tex_task'] = $designTexStepTaskList[$item['entity_id']] ?? null;
            $item['name'] = isset($entityNameList[$item['entity_id']]) ? $entityNameList[$item['entity_id']] . '/' . $item['name'] : $item['name'];
            return $item;
        }, $res);
    }

    /**
     * 处理待办过滤条件
     * @param $data
     * @param $taskStatus
     * @param $userId
     * @return mixed
     * @throws Exception
     */
    public function getTaskMemberFilter($data, $taskStatus, $userId)
    {
        $statusService = StatusService::getInstance();
        $taskStatusMap = array_column($taskStatus, 'id', 'code');
        $statusIdList = model(StatusModel::class)->where(['code' => ['NOT IN', 'final,closed']])->field('id')->select();
        switch ($data['status_code']) {
            case "all":
                $data[] = [
                    [
                        [
                            'task_member.user_id' => $userId,
                            'task_member.partner' => $userId,
                            '_logic' => 'or'
                        ],
                        'task_member.status' => $statusService->getTaskDefaultStatus()['id']
                    ],
                    '_logic' => 'or',
                    [
                        'task.created_by' => $userId,
                        "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $statusService->getTaskDefaultStatus()['id']
                    ]
                ];
                break;
            case "not_started":
                $data[] = ['task_member.user_id' => $userId, 'task_member.status' => $taskStatusMap[$data['status_code']]];
                break;
            case "created":
                $data[] = ['task.created_by' => $userId, "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $statusService->getTaskDefaultStatus()['id']];
                break;
            case "partner":
                $data[] = ['task_member.partner' => $userId, 'task_member.status' => $statusService->getTaskDefaultStatus()['id']];
                break;
            case "closed":
            case "final":
                $data[] = [
                    [
                        [
                            'task_member.user_id' => $userId,
                            'task_member.partner' => $userId,
                            '_logic' => 'or'
                        ],
                        'task_member.status' => $taskStatusMap[$data['status_code']]
                    ],
                    '_logic' => 'or',
                    [
                        'task.created_by' => $userId,
                        "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $taskStatusMap[$data['status_code']]
                    ]
                ];
                break;
            case "expired":
                $data[] = [
                    [
                        [
                            'task_member.user_id' => $userId,
                            'task_member.partner' => $userId,
                            '_logic' => 'or'
                        ],
                        'task_member.status' => $statusService->getTaskDefaultStatus()['id']
                    ],
                    '_logic' => 'or',
                    [
                        'task.created_by' => $userId,
                        "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $statusService->getTaskDefaultStatus()['id']
                    ],
                ];
                $data["task.plan_end_time"] = [['LT', time()], ['NEQ', 0]];
                break;
            case "complete":
                $data[] = [
                    [
                        'task_member.user_id' => $userId,
                        'task_member.partner' => $userId,
                        '_logic' => 'or'
                    ]
                ];
                break;
            case "not-final":
                $data[] = [
                    [
                        [
                            [
                                'task_member.user_id' => $userId,
                                'task_member.partner' => $userId,
                                '_logic' => 'or'
                            ],
                            'task_member.status' => $statusService->getTaskDefaultStatus()['id']
                        ],
                        '_logic' => 'or',
                        [
                            'task.created_by' => $userId,
                            "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $statusService->getTaskDefaultStatus()['id']
                        ],
                    ]
                ];
                $data["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))"] = ['IN', array_column($statusIdList, 'id')];
                break;
        }
        unset($data['status_code']);
        return $data;
    }

    /**
     * 查询状态的所有条数
     * @param $userId
     * @param $tenantId
     * @return array
     * @throws \think\Exception
     */
    public function selectStatusTotal($userId, $tenantId)
    {
        $res = [];
        $statusService = StatusService::getInstance();
        $taskStatus = $statusService->getList([], "*");
        $taskStatusMap = array_column($taskStatus, 'id', 'code');
        $model = model(TaskMemberModel::class);
        $joinModel = "task ON task_member.task_id = task.id";
        $status = [
            'all' => [
                [
                    [
                        'task_member.user_id' => $userId,
                        'task_member.partner' => $userId,
                        '_logic' => 'or'
                    ],
                    'task_member.status' => $taskStatusMap['not_started']
                ],
                '_logic' => 'or',
                [
                    'task.created_by' => $userId,
                    "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $taskStatusMap['not_started']
                ]
            ],
            'not_started' => ['task_member.user_id' => $userId, 'task_member.status' => $taskStatusMap['not_started']],
            'created' => ['task.created_by' => $userId, "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $taskStatusMap['not_started']],
            'partner' => ['task_member.partner' => $userId, 'task_member.status' => $taskStatusMap['not_started']],
            'closed' => [
                [
                    [
                        'task_member.user_id' => $userId,
                        'task_member.partner' => $userId,
                        '_logic' => 'or'
                    ],
                    'task_member.status' => $taskStatusMap['closed']
                ],
                '_logic' => 'or',
                [
                    'task.created_by' => $userId,
                    "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $taskStatusMap['closed']
                ]
            ],
            'final' => [
                [
                    [
                        'task_member.user_id' => $userId,
                        'task_member.partner' => $userId,
                        '_logic' => 'or'
                    ],
                    'task_member.status' => $taskStatusMap['final']
                ],
                '_logic' => 'or',
                [
                    'task.created_by' => $userId,
                    "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => $taskStatusMap['final']
                ]
            ]
        ];
        $filter['task.entity_module_id'] = module_by_code('todo')['id'];
        $filter['task.tenant_id'] = $tenantId;
        $filter['step_type'] = ['NEQ', 'standard_make_to_do'];
        $res['all'] = $model->where([$status['all'], $filter])->join($joinModel)->count('distinct task_id'); // 全部状态的待办
        $res['not_started'] = $model->where([$status['not_started'], $filter])->join($joinModel)->count(); // 待处理的
        $res['created'] = $model->where([$status['created'], $filter])->join($joinModel)->count('distinct task_id'); // 我创建的
        $res['partner'] = $model->where([$status['partner'], $filter])->join($joinModel)->count(); // 仅我参与的
        $res['final'] = $model->where([$status['final'], $filter])->join($joinModel)->count('distinct task_id'); // 已完成的
        $res['closed'] = $model->where([$status['closed'], $filter])->join($joinModel)->count('distinct task_id'); // 已取消的
        return $res;
    }

    /**
     * 更新待办任务
     * @param $data
     * @param $userId
     * @param bool $isExternalChange
     * @return array
     * @throws \Throwable
     * @throws \think\Exception
     */
    public function updateTask($data, $userId, $isExternalChange = false)
    {
        //兼容以前的时间传递方式
        if (!empty($data['task']['plan_start_time']) && is_numeric($data['task']['plan_start_time'])) {
            $data['task']['plan_start_time'] = date('Y-m-d H:i:s', $data['task']['plan_start_time']);
        }
        if (!empty($data['task']['plan_end_time']) && is_numeric($data['task']['plan_end_time'])) {
            $data['task']['plan_end_time'] = date('Y-m-d H:i:s', $data['task']['plan_end_time']);
        }

        if (!empty($data['executor_list'])) {
            $data['executor_list'] = $this->execGroupUserList($data['executor_list']);
        }
        $commonService = CommonService::instance("task");
        $commonService->setCurrentModuleCode("task");
        $task = $commonService->find(['filter' => ['id' => $data['task']['id']]]);
        $model = model(TaskClockModel::class);
        $taskMember = model(TaskMemberModel::class);
        $res = [];
        $clockIds = [];
        $taskClock = [];
        $taskClockTime = [];
        $taskClockUser = [];

        //判定是否是外部修改代办
        $updatePlanData = [];
        $plan = [];
        if ($isExternalChange) {
            $updateData = $data['task'];

            unset($updateData['id'], $updateData['plan_end_time'], $updateData['plan_start_time']);

            // 判定是否有plan
            $plan = model(PlanModel::class)->where(['task_id' => $data['task']['id']])->find();

            if (!empty($plan)) {
                $updatePlanData = [
                    'id' => $plan['id']
                ];
            }

            //只有计划时间能更改,且有排期的待办计划交付时间大于排期的时间(也是任务的时间)必定会进行延期
            if (!empty($updateData) || (!empty($data['task']['plan_end_time']) && !empty($task['plan_end_time']) && strtotime($data['task']['plan_end_time']) > $task['plan_end_time'])) {
                // 并且不是模板待办
                if (!empty($plan) && empty($data['task']['template_todo_id'])) {
                    throw new LogicException("you have plan can't change todo task", ErrorCode::PLAN_TODO_TASK_CAN_NOT_CHANGE);
                }
            }
        }

        //如有计划开始
        //如有时间计划更改 需要延期检测
        if ((!empty($data['task']['plan_start_time']) && ($task['plan_start_time'] != strtotime($data['task']['plan_start_time']))) ||
            (!empty($data['task']['plan_end_time']) && ($task['plan_end_time'] != strtotime($data['task']['plan_end_time'])))) {

            if (!empty($updatePlanData)) {
                if (!empty($data['task']['plan_start_time']) && ($task['plan_start_time'] != strtotime($data['task']['plan_start_time']))) {
                    $updatePlanData['start_time'] = $data['task']['plan_start_time'];
                }

                if (!empty($data['task']['plan_end_time']) && ($task['plan_end_time'] != strtotime($data['task']['plan_end_time']))) {
                    $updatePlanData['end_time'] = $data['task']['plan_end_time'];
                }
            }
            ReviewRequestService::getInstance()->checkDelay($task['id']);
        }

        //计划开始时间置空
        if (isset($data['task']['plan_end_time']) && empty($data['task']['plan_end_time'])) {
            $data['task']['plan_end_time'] = '0000-00-00';
        }

        //闹钟处理
        if (isset($data['task']['notify_config'])) {
            $data['task']['task_notify_config'] = $data['task']['notify_config'];
            $clock = $model->where([
                'task_id' => $data['task']['id'],
                'type' => "to_do"
            ])->select();
            $clockMap = array_column($clock, null, 'time');
            $data['task']['task_clock_time'] = [];
            foreach ($data['task']['notify_config'] as $notifyConfigItem) {
                if ($notifyConfigItem['type'] == 'timestamp') {
                    $data['task']['task_clock_time'][] = $notifyConfigItem['value'];
                }
                if ($notifyConfigItem['type'] == 'code') {
                    $notifyConfigItem = explode('end_', $notifyConfigItem['value']);
                    $data['task']['task_clock_time'][] = strtotime("-{$notifyConfigItem[1]} minute", strtotime($data['task']['plan_end_time']));
                }
            }
            foreach ($data['task']['task_clock_time'] as $clockTime) {
                if (!isset($clockMap[$clockTime])) {
                    $taskClock[] = [
                        'task_id' => $data['task']['id'],
                        'time' => $clockTime,
                        'created_by' => $userId,
                        'created' => time(),
                        'type' => TaskModel::STEP_TYPE_TO_DO
                    ];
                    $taskClockTime[] = $clockTime;
                } else {
                    unset($clockMap[$clockTime]);
                }
            }

            if (!empty($clockMap)) {
                $clockIds = implode(",", array_column($clockMap, 'id'));
            }
        }

        $taskStatus = 0;
        $allocationMember = $this->getDealTaskMemberData($data, $taskStatus);


        //新增的闹钟用户,只用于提示当前任务的
        if (!empty($allocationMember['need_add'])) {
            foreach ($allocationMember['need_add'] as $addItem) {
                if ($addItem['task_id'] == $data['task']['id']) {
                    $taskClockUser[] = $addItem['user_id'] > 0 ? $addItem['user_id'] : ($addItem['partner'] > 0 ? $addItem['partner'] : $addItem['starter']);
                }
            }
        }

        $addTaskMemberWhere = [];
        if (!empty($allocationMember['need_add_relation'])) {
            $addTaskMemberWhere = $this->getTaskMemberAllUserIds($allocationMember['need_add'], 'user_task_member_filter');
        }

        $relateTagData = [];
        if (isset($data['relate_tag'])) {
            $relateTagData = TaskRelationTagService::getInstance()->getUpdateTodoTaskRelateTagData($task['id'], $data['relate_tag'], $task['tenant_id'], $userId);
        }

        //环节排期的不能更新标签
        if ($isExternalChange && !empty($plan) && $plan['type'] == PlanModel::TYPE_STEP_CATEGORY && empty($data['task']['template_todo_id']) && (!empty($relateTagData['add_tag']) || !empty($relateTagData['delete_tag']))) {
            throw new LogicException("you have plan can't change todo task", ErrorCode::PLAN_TODO_TASK_CAN_NOT_CHANGE);
        }

        $mediaService = MediaService::getInstance();
        // 开启事务
        $model->startTrans();
        try {
            $data = $mediaService->handleMediaItemUpload($data, 'task', model(TaskModel::class));
            //删除闹钟
            if (!empty($clockIds)) {
                $model->delete($clockIds);
            }
            //添加闹钟
            if (!empty($taskClock)) {
                $res['task_clock'] = $model->addAll($taskClock);
            }
            //新增成员
            if (!empty($allocationMember['need_add'])) {
                $taskMember->addAll($allocationMember['need_add']);
            }
            //修改成员
            if (!empty($allocationMember['need_update'])) {
                $taskMember->saveAll($allocationMember['need_update']);
            }
            //删除成员
            if (!empty($allocationMember['need_delete'])) {
                $taskMember->where(['id' => ['IN', $allocationMember['need_delete']]])->delete();
            }

            //补充task_member_id到task_member_relation
            if (!empty($allocationMember['need_add_relation']) && !empty($addTaskMemberWhere)) {
                $addTaskMemberList = $taskMember->where($addTaskMemberWhere)->select();
                // 补齐task_member_id
                $addTaskMemberMap = $this->getTaskMemberAllUserIds($addTaskMemberList, 'task_user_map');
                foreach ($allocationMember['need_add_relation'] as $needAddRelationIndex => $needAddRelationItem) {
                    $needAddRelationItem['task_member_id'] = $addTaskMemberMap[$needAddRelationItem['task_id'] . "-" . $needAddRelationItem['user_id']]['id'];
                    $allocationMember['need_add_relation'][$needAddRelationIndex] = $needAddRelationItem;
                }
            }

            //新增关联
            if ((!empty($allocationMember['task_member_need_add_relation']) || !empty($allocationMember['need_add_relation'])) &&
                !(empty($allocationMember['task_member_need_add_relation']) && empty($allocationMember['need_add_relation']))) {
                $needAddRelation = array_merge($allocationMember['task_member_need_add_relation'], $allocationMember['need_add_relation']);
                /**
                 * 防止前端传相同数据
                 * 所以做去除重复处理
                 */
                $needAddRelationTmp = [];
                foreach ($needAddRelation as $needAddRelationItem) {
                    $tmpKey = join('#', array_values($needAddRelationItem));
                    $needAddRelationTmp[$tmpKey] = $needAddRelationItem;
                    unset($tmpKey);
                }
                $needAddRelation = array_values($needAddRelationTmp);
                model(TaskMemberRelationModel::class)->addAll($needAddRelation);
            }

            //删除关联
            if (!empty($allocationMember['need_delete_relation'])) {
                model(TaskMemberRelationModel::class)->where(["id" => ["IN", $allocationMember['need_delete_relation']]])->delete();
            }

            if (!empty($data['starter_list'])) {
                $data['task']['starter_list'] = $data['starter_list'];
            }
            if (!empty($data['executor_list'])) {
                $data['task']['executor_list'] = $data['executor_list'];
            }

            if ($this->isExistTaskChange($data['task'])) {
                TaskLockService::getInstance()->TaskLockedCheckUpdateData($data['task']['id'], $data['task']);
                $res['task'] = $commonService->update($data['task'], '', false);
            }

            if (count($updatePlanData) > 1) {
                model(PlanModel::class)->modifyItem($updatePlanData);
            }

            //添加标签
            if (!empty($relateTagData['add_tag'])) {
                model(TaskRelationTagModel::class)->addAll($relateTagData['add_tag']);
            }

            //删除标签
            if (!empty($relateTagData['delete_tag'])) {
                model(TaskRelationTagModel::class)->where(['id' => ["IN", $relateTagData['delete_tag']]])->delete();
            }

            $model->commit();

            if ($task['step_type'] === 'work_order_to_do' && (!empty($allocationMember["need_add_executor"]) || !empty($allocationMember["need_delete_executor"]))) {
                $this->notifyTaskWorkOrderTodoExecutorChanged($task, [
                    'add' => $allocationMember["need_add_executor"] ?? null,
                    'del' => $allocationMember["need_delete_executor"] ?? null,
                ]);
            }

            // 如果任务没发生更新就不会返回数据
            if (empty($res['task'])) {
                $res['task'] = $task;
            }
            // 是否有新增闹钟,有新增闹钟则再全部通知一遍
            if (!empty($taskClock)) {
                $taskClockUser = $taskMember->where(['task_id' => $data['task']['id']])->select();
                $taskClockUser = $this->getTaskMemberAllUserIds($taskClockUser);
                $this->notifyTaskMemberUser($res['task'], $taskClockUser, $taskClockTime);
            } elseif (!empty($taskClockUser)) { // 如果有新拉进来的用户就直接发送提醒
                $this->notifyTaskMemberUser($res['task'], $taskClockUser);
            }

            return $res;
        } catch (Throwable $e) {
            $model->rollback();
            throw $e;
        }
    }

    /**
     * 更新待办任务状态
     * @param $data
     * @param $userId
     * @return array|bool|int|string
     * @throws Throwable
     * @throws \think\Exception
     */
    public function updateStatus($data, $userId)
    {
        $res = [];
        $statusService = StatusService::getInstance();
        $taskStatus = $statusService->getOne(['code' => $data['code']], "id");
        $doneStatus = $statusService->getTaskDoneStatus();
        if (!empty($taskStatus)) {
            $data['status'] = $taskStatus['id'];
            if ($taskStatus['id'] == $doneStatus['id']) {
                // 验证交付文件是否全部上传，获取交付文件列表
                $taskTemplateJson = model(TaskModel::class)->where(['id' => $data['id']])->field("id, json_unquote(json_extract(json,'$.template_todo_info')) as template_todo_info")->find();
                if (!empty($taskTemplateJson['template_todo_info'] ?? [])) {
                    $taskTemplateJson = json_decode($taskTemplateJson['template_todo_info'], true);
                    // 取固化交付列表 file_list
                    $deliveryList = $taskTemplateJson['file_list'] ?? [];
                    // 取上传状态
                    $deliveryList = $this->getDeliveryCurrent($deliveryList, null, $data['id']);
                    foreach (($deliveryList['delivery_list'] ?? []) as $item) {
                        if (empty($item['cos_media'] ?? [])) {
                            throw new LogicException('delivery file list not fully uploaded', ErrorCode::DELIVERY_FILELIST_NOT_FULLY_UPLOADED);
                        }
                    }
                }
                $data['end_time'] = time();
                $data['delivery_time'] = time();
            }
        }
        $model = model(TaskMemberModel::class);
        $commonService = CommonService::instance("task");
        $commonService->setCurrentModuleCode("task");
        $defaultStatus = $statusService->getTaskDefaultStatus();
        $closedStatus = $statusService->getTaskDefaultClosedStatus();

        // 查询主待办下的事项衍生任务
        $subTodoList = DismantleTaskService::getInstance()->getDismantleTaskIds([$data['id']], TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO);
        if (!empty($subTodoList)) {
            $templateTodoSubTaskIds = array_column($subTodoList, 'id');
            $templateTodoSubTaskIds = array_merge($templateTodoSubTaskIds, [intval($data['id'])]); // 拼上主待办id
        }
        $model->startTrans();
        try {
            // 完成分配给自己的待办任务
            if ($data['type'] == 'single') {
                $singleWhere = [];
                // 立即完成，只完成执行人是自己的
                if ($data['code'] == 'final') {
                    $singleWhere = ['task_id' => $data['id'], 'user_id' => $userId];
                }
                // 任何人都可以重启代办
                if ($data['code'] == 'not_started') {
                    $singleWhere = ['task_id' => $data['id']];
                }
                $taskMember = $model->where($singleWhere)->find();
                $res = $model->where(['id' => $taskMember['id']])->save(['status' => $data['status'], 'updated' => time()]);
                if ($res) {
                    $status = [
                        $defaultStatus['id'],
                        $closedStatus['id']
                    ];
                    $taskMemberList = $model->where(['task_id' => $data['id'], 'status' => ['IN', $status], 'user_id' => ['gt', 0]])->select();
                    // 如果单个完成任务后检查到已经没有未完成的用户，那么就默认修改全员任务状态
                    if (empty($taskMemberList)) {
                        $data['task']['task_status'] = $data['status'];
                        $data['task']['end_time'] = time();
                        $data['task']['id'] = $data['id'];
                        $data['task']['task_notify_config'] = [];
                        $taskMember = $model->field('id')->where(['task_id' => $data['id'], 'status' => ['IN', $status]])->select();
                        if (!empty($taskMember)) {
                            $taskMemberId = array_column($taskMember, 'id');
                            $res = $model->where(['id' => ['IN', $taskMemberId]])->save(['status' => $data['status'], 'updated' => time()]);
                        }
                        // 任务锁定时检测更新的数据
                        TaskLockService::getInstance()->TaskLockedCheckUpdateData($data['task']['id'], $data);
                        $commonService->update($data['task']);
                        $this->deleteTaskClock($data);
                    }
                }
            } else if ($data['type'] == 'multiple') { // 由我发起的任务点击已完成
                $data['task']['task_status'] = $data['status'];
                $data['task']['end_time'] = time();
                $data['task']['id'] = $data['id'];
                $data['task']['task_notify_config'] = [];
                // 任务锁定时检测更新的数据
                TaskLockService::getInstance()->TaskLockedCheckUpdateData($data['task']['id'], $data);
                $commonService->update($data['task']);
                // 完成以后消除所有提醒时间
                $this->deleteTaskClock($data);
                // 分配出去的任务全部默认完成
                $taskMember = $model->field('id')->where(['task_id' => $data['id']])->select();
                if (!empty($taskMember)) {
                    $taskMemberId = array_column($taskMember, 'id');
                    $res = $model->where(['id' => ['IN', $taskMemberId]])->save(['status' => $data['status'], 'updated' => time()]);
                }
            }
            // 已完成,已取消同步子任务状态
            $this->updateSubTodoStatus($data, $taskStatus['id']);

            $model->commit();
            if ($res) {
                try {
                    // 发成待办发送消息到会话窗口
                    $this->statusChangeSendMessage($data['id'], $data['code']);
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
            }
            $taskData = model(TaskModel::class)->find($data['id']);
            if (!empty($templateTodoSubTaskIds)) {
                $taskData['template_todo_sub_task_ids'] = $templateTodoSubTaskIds;
            }
            return $taskData;
        } catch (Throwable $e) {
            $model->rollback();
            throw $e;
        }
    }


    /**
     * 状态变更发送消息到群组
     * @param $taskId
     * @param $type
     * @return array|void
     */
    function statusChangeSendMessage($taskId, $type)
    {
        // 获取工单id
        $taskData = model(TaskModel::class)->field('name,json')->where(['id' => $taskId])->find();
        $taskId = json_decode($taskData['json'], 'true')['task_work_order_id'] ?? '';

        if (empty($taskId)) {
            return [];
        }
        // 默认状态变更
        $contentType = 'change_work_order_chat_status ';
        if ($type == 'final') {
            // 完成
            $contentType = 'final_work_order_chat';
        } else if ($type == 'closed') {
            $contentType = 'closed_work_order_chat';
        }
        $taskOrderData = model(TaskWorkOrderModel::class)->field('id,number,chat_global_id,name,status')
            ->where(['id' => $taskId])
            ->where("chat_global_id !=''")
            ->find();
        $workOrderUserList = model(TaskWorkOrderUserModel::class)->field('user_id')
            ->where(['work_order_id' => $taskOrderData['id']])->select();
        $saasUserIds = array_column($workOrderUserList, 'user_id');
        $imUserList = model(UserModel::class)->field('union_id')->where(['id' => ['IN', $saasUserIds]])->select();
        $imUserIds = array_column($imUserList, 'union_id');

        if (count($imUserIds) >= 2 && !empty($taskOrderData)) {
            $requestData = [
                "data" => [
                    'receives' => $imUserIds,
                    'content_type' => $contentType,
                    'global_id' => $taskOrderData['chat_global_id'],
                    'content_extra_data' => ['work_order_id' => $taskOrderData['id'], 'work_order_name' => $taskData['name'], 'status' => $taskOrderData['status']]
                ]
            ];
            return teamones_request('teamones-im', 'message/push_work_order_chat_message', $requestData);
        }

    }

    /**
     * 查找指定待办任务
     * @param $param
     * @param $userId
     * @return array
     * @throws Exception
     */
    public function find($param, $userId)
    {
        $res = [];
        $filter = $param['filter'];
        $taskQueryFields = [
            "task.id",
            "task.entity_id",
            "task.description",
            "task.name",
            "task.step_type",
            "task.plan_end_time",
            "task.plan_start_time",
            "task.plan_delivery_time",
            "task.end_time",
            "task.created_by",
            "task.json",
            "task.tenant_id",
            'task.created',
            'task.step_id',
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) as status_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_stage_id')) AS stage_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_work_order_id')) AS work_order_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.is_sub_todo')) AS is_sub_todo", // 是否子待办
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.parent_todo_task_id')) AS parent_todo_task_id", // 主待办id
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.template_todo_parent_task_id')) AS template_todo_parent_task_id", // 模板待办主待办id
            "user.name as created_name",
            "user.avatar",
            "user.union_id",
            "project.name as project_name",
            "project.id as project_id",
            "CAST(JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.starter_list[0].user_list[0].user_id')) as SIGNED ) as starter_user_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.template_todo_parent_task_id')) as template_todo_parent_task_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.department_partner_list')) as department_partner_list",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.department_executor_list')) as department_executor_list",
        ];
        $task = model(TaskModel::class) //根据任务id查出task,user,project表中的信息
        ->field($taskQueryFields)
            ->join('user ON task.created_by = user.id')
            ->join("project ON task.project_id = project.id", 'LEFT')
            ->where(['task.id' => $filter['id']])
            ->find();

        if (empty($task)) {
            throw_strack_exception('task not found', ErrorCode::TASK_NOT_FOUND);
        }

        if (!empty($task['department_partner_list'])) {
            $res['department_partner_list'] = json_decode($task['department_partner_list']);
        }

        if (!empty($task['department_executor_list'])) {
            $res['department_executor_list'] = json_decode($task['department_executor_list']);
        }

        if ($task['template_todo_parent_task_id']) {
            $templateTodoTata = model(TaskModel::class)->where(['id' => $task['template_todo_parent_task_id']])->field('id,name')->find();
            $task['template_todo_parent_task_name'] = $templateTodoTata['name'] ?? '';
        }
        $statusService = StatusService::getInstance();
        $taskStatus = $statusService->getList([], "*"); //查出状态表Status中所有信息
        $taskStatusMap = array_column($taskStatus, null, 'id');
        // 获取提醒时间
        $taskClock = model(TaskClockModel::class)->where(['task_id' => $task['id']])->select();
        $task['task_clock_time'] = [];
        if (!empty($taskClock)) {
            $taskClockMap = array_column($taskClock, 'time');
            $task['task_clock_time'] = $taskClockMap;
        }
        // 转json
        if (!empty($task['json'])) {
            $json = json_decode($task['json'], true);
            $json['task_status'] = $taskStatusMap[$json['task_status']]['code'];
            $json['is_lock'] = $json['is_lock'] ?? 'no';
            unset($task['json']);
            $task = array_merge($task, $json);
        }
        $res['task'] = $task;
        // 查询任务附件
        $taskCosMedia = $task['task_cos_media'] ?? '';
        $cosMediaList = [];
        if (!empty($taskCosMedia)) {
            $cosMediaList = model(CosMediaModel::class)->where(['id' => ['IN', $taskCosMedia]])->select();
            $cosMediaList = array_map(function ($cosMediaItem) {
                $cosMediaItem['param'] = json_decode($cosMediaItem['param']);
                return $cosMediaItem;
            }, $cosMediaList);
        }
        $res['task_cos_media'] = $cosMediaList;
        $taskMemberList = model(TaskMemberModel::class)->field('id,user_id,partner,status')->where(['task_id' => $filter['id']])->select(); //根据任务id查出task_member待办任务表中的信息
        // 统计执行者个数
        $executorIds = array_column($taskMemberList, 'user_id'); //拿到待办任务中有几个执行者的id
        $executor = model(UserModel::class)->field('id,name')->where(['id' => ['IN', implode(',', $executorIds)]])->select();//跟据待办任务表中查出的执行者的id去用户表中查出名字跟id
        $res['executor']['total'] = count($executor);

        // 查询参与者列表并统计个数
        $partnerIds = array_column($taskMemberList, 'partner'); //拿到user_id
        $partners = model(UserModel::class)->field('id,name,avatar,union_id')->where(['id' => ['IN', implode(',', $partnerIds)]])->select();
        $res['partner']['total'] = count($partners);

        // 待办任务中执行人即是参与人，因此遍历参与者信息即可
        $partners = array_column($partners, null, 'id');
        foreach ($taskMemberList as $key => $value) {
            if (empty($value['partner']) && empty($value['user_id'])) {
                continue;
            }
            if (array_key_exists($value['user_id'], $partners)) {//判断$value['user_id']是否存在$partners数组里面
                $res['executor']['rows'][$key]['id'] = $partners[$value['user_id']]['id'];
                $res['executor']['rows'][$key]['name'] = $partners[$value['user_id']]['name'];
                $res['executor']['rows'][$key]['avatar'] = $partners[$value['user_id']]['avatar'];
                $res['executor']['rows'][$key]['status'] = $taskStatusMap[$value['status']]['code'];
                $res['executor']['rows'][$key]['is_deleted'] = $value['user_id'] == $task['created_by'];
                $res['executor']['rows'][$key]['union_id'] = $partners[$value['user_id']]['union_id'];
            }
            $res['partner']['rows'][$key]['id'] = $partners[$value['partner']]['id'];
            $res['partner']['rows'][$key]['name'] = $partners[$value['partner']]['name'];
            $res['partner']['rows'][$key]['union_id'] = $partners[$value['partner']]['union_id'];
            $res['partner']['rows'][$key]['is_deleted'] = $value['user_id'] == $task['created_by'];
            $res['partner']['rows'][$key]['avatar'] = $partners[$value['user_id']]['avatar'] ?? null;

            if ($value['user_id'] == $userId) {
                $res['task']['status'] = $taskStatusMap[$value['status']]['code'];
            }
        }
        if (isset($res['executor']['rows'])) {
            $is_deleted = array_column($res['executor']['rows'], "is_deleted");
            array_multisort($is_deleted, SORT_DESC, $res['executor']['rows']);
        }
        if (isset($res['partner']['rows'])) {
            $is_deleted = array_column($res['partner']['rows'], "is_deleted");
            array_multisort($is_deleted, SORT_DESC, $res['partner']['rows']);
        }
        // 查询贴图任务 实体信息
        if ($task['step_type'] === TaskModel::STEP_TYPE_ENTITY_TO_DO) {
            $entityName = model(EntityModel::class)->where(['id' => $task['entity_id']])->value('name');
            $res['task']['name'] = !empty($entityName) ? $entityName . '/' . $res['task']['name'] : $res['task']['name'];
        }

        // 环节
        $res['step_category_ids'] = model(TaskRelationTagModel::class)->where(['task_id' => $task['id'], 'link_module_code' => ['IN', ['step_category', 'show_step_category']]])->column('link_id');

        //环节详情
        if (!empty($res['step_category_ids'])) {
            $resStepCategoryIds = $res['step_category_ids'];
            $showStepCategoryList = TemplateService::getInstance()->findStepCategoryShowList();
            $res['step_category_info'] = array_values(array_filter($showStepCategoryList, function ($showStepCategoryItem) use ($resStepCategoryIds) {
                return in_array($showStepCategoryItem['id'], $resStepCategoryIds);
            }));
        }

        // 阶段
        if (!empty($task['task_stage_id'])) {
            $taskStage = StageService::getInstance()->getStageListLite(['id' => $task['task_stage_id']]);
            if (!empty($taskStage)) {
                $res['task_stage'] = array_shift($taskStage);
            }
            if (!empty($res['task_stage']['step_category_id'])) {
                $resStepCategoryIds = explode(',', $res['task_stage']['step_category_id']);
                $showStepCategoryList = TemplateService::getInstance()->findStepCategoryShowList();
                $res['task_stage']['step_category_info'] = array_values(array_filter($showStepCategoryList, function ($showStepCategoryItem) use ($resStepCategoryIds) {
                    return in_array($showStepCategoryItem['id'], $resStepCategoryIds);
                }));
            }
        }

        // 文件
        $res['file_list'] = [];
        if (!empty($task['template_todo_info']['file_list'])) {
            $res['file_list'] = $task['template_todo_info']['file_list'];
            $deliveryList = TaskMemberService::getInstance()->getDeliveryCurrent($res['file_list'], null, $task['id']);
            if (!empty($deliveryList['number'])) {
                $res['file_list'] = $deliveryList['delivery_list'];
                unset($deliveryList['delivery_list']);
                $res['file_list_version'] = $deliveryList;
            }
        }

        //查询计划
        $plan = model(PlanModel::class)
            ->where([
                'task_id' => $task['id']
            ])
            ->field("id,type,entity_id,start_time,end_time")
            ->find();

        if (!empty($plan)) {
            $res['plan'] = $plan;
        }
        // 累计工时
        $workRecordTimeData = WorkTimeRecordService::getInstance()->getTaskWorkTimeRecord($task['id']);
        $res['cumulative_work_time'] = $workRecordTimeData['count_sum'] ?? 0;

        $stepId = $task['step_id'] ?? 0;
        // 实体信息
        $workOrderData = model(TaskWorkOrderModel::class)->where(['id' => $task['work_order_id']])->find();
        if (!empty($workOrderData)) {
            $entityData = model(EntityModel::class)->join("module on entity.module_id = module.id")
                ->where(['entity.id' => $workOrderData['entity_id']])
                ->field("initial_episode_code,showings_number,entity.`name`,JSON_UNQUOTE(JSON_EXTRACT(entity.json, CONCAT('$.', module.code, '_grade'))) as grade")
                ->find();
            if (!empty($entityData)) {
                $res['entity_info'] = $entityData;
                $stepId = $workOrderData['step_id'];
            }
        }

        // 工序
        $stepData = model(StepModel::class)->where(['id' => $stepId])->field('id,name,code')->find();
        if (!empty($stepData)) {
            $res['step_info'] = $stepData;
        }


        //查找任务状态
        $status = model(StatusModel::class)->where(['id' => $task['status_id']])->field("id,code,color,icon,name")->find();
        $res['status'] = $status;
        // 查找集交付时间
//        $planData = model(PlanModel::class)->where(['task_id' => $task['id']])->field('end_time')->find();
//        $res['task']['plan_delivery_time'] = $planData['end_time'] ?? '';

        // 查询子任务
        $subTodoList = DismantleTaskService::getInstance()->getDismantleTaskIds([$task['id']], TaskRelationModel::RELATION_TYPE_SUB_TODO);
        $res['sub_todo_ids'] = [];
        if (!empty($subTodoList)) {
            $res['sub_todo_ids'] = array_column($subTodoList, 'id');
        }
        // 如果是子任务,则查询主任务信息
        if (!empty($res['task']['parent_todo_task_id'])) {
            $taskInfo = model(TaskModel::class)
                ->where(['task.id' => $res['task']['parent_todo_task_id']])
                ->field('id,name')
                ->find();
            $res['main_task_info'] = [];
            if (!empty($taskInfo)) {
                $res['main_task_info'] = $taskInfo;
            }
        }
        // 查询模板待办
        $subTodoList = DismantleTaskService::getInstance()->getDismantleTaskIds([$task['id']], TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO);
        $res['template_todo_ids'] = [];
        if (!empty($subTodoList)) {
            $res['template_todo_ids'] = array_column($subTodoList, 'id');
        }

        // 查剧集下的计划
        $planData = $this->planModel
            ->where(['task_id' => $task['id']])
            ->field('id,tenant_id,project_id,start_time,end_time,type,task_id,scope')
            ->find();

        // 查询关联项
        $taskTagRelationResult = TaskRelationTagService::getInstance()->getTaskRelationListDetail($task['id']);
        if (!empty($planData['scope']) && $planData['scope'] == PlanModel::SCOPE_SINGLE) {
            if (isset($taskTagRelationResult['episode'][0])) {
                $res['ep_name'] = $taskTagRelationResult['episode'][0]['code'];
                $res['ep_list'] = [$taskTagRelationResult['episode'][0]['code']];
                $res['ep_id'] = $taskTagRelationResult['episode'][0]['id'];
            }
        } else {
            if (!empty($taskTagRelationResult['episode'])) {
                $res['ep_count'] = count($taskTagRelationResult['episode']) . "集";
            }
            $res['ep_list'] = array_column($taskTagRelationResult['episode'], 'code');
            $res['ep_name'] = PlanModel::SCOPE_GLOBAL;
            $res['ep_id'] = PlanModel::SCOPE_GLOBAL;
        }
        $res['todo_relation_id'] = $taskTagRelationResult['episode'][0]['id'] ?? 0;
        //是否延期
        $taskDelayMap = ReviewTaskDelayService::getInstance()->taskDelayInfo([$task['id']]);
        $res['is_task_delay'] = !empty($taskDelayMap[$task['id']]);
        // 延期时间
        $res['task_delay_time'] = $taskDelayMap[$task['id']]['task_delay_time'] ?? 0;
        $res['task_delay_reason'] = $taskDelayMap[$task['id']]['task_delay_reason'] ?? null;
        return $res;
    }


    /**
     * 查找任务成员
     * @param $param
     * @return array
     */
    public function getTaskMemberList($param)
    {
        $res = [];
        $filter = $param['filter'] ?? [];
        $page = $param['page'] ?? [];
        if (empty($page) && !isset($filter['task_id'])) {
            $page = [1, C("database.database_max_select_rows")];
        }
        if (empty($filter)) {
            return $res;
        }
        $taskMemberQuery = model(TaskMemberModel::class)
            ->where($filter)
            ->field("task_id, user_id, partner, status");
        if (!empty($page)) {
            $taskMemberQuery = $taskMemberQuery->page(...$page);
        }
        $taskMemberList = $taskMemberQuery->select();
        $userIdList = [];
        $taskMemberMap = [];
        foreach ($taskMemberList as $item) {
            $taskMemberMap[$item['task_id']]['executor'][] = $item;
            $taskMemberMap[$item['task_id']]['partner'][] = $item;
            $userIdList[$item['user_id']] = $item['user_id'];
            $userIdList[$item['partner']] = $item['partner'];
        }
        if (empty($userIdList)) {
            return $res;
        }
        $userList = model(UserModel::class)
            ->where(['id' => ['in', array_values($userIdList)]])
            ->field('id, name, union_id, avatar')
            ->select();
        $userMap = array_column($userList, null, 'id');
        foreach ($taskMemberMap as $taskId => $item) {
            $taskUserList = [
                'executor' => [],
                'partner' => [],
            ];
            foreach ($item['executor'] as $user) {
                if (isset($userMap[$user['user_id']])) {
                    $userMap[$user['user_id']]['status'] = $user['status'];
                    $taskUserList['executor'][$user['user_id']] = $userMap[$user['user_id']];
                }
            }
            foreach ($item['partner'] as $user) {
                if (isset($userMap[$user['partner']])) {
                    $userMap[$user['partner']]['status'] = $user['status'];
                    $taskUserList['partner'][$user['partner']] = $userMap[$user['partner']];
                }
            }
            $res[] = [
                'task_id' => $taskId,
                'member' => [
                    'executor' => array_values($taskUserList['executor']),
                    'partner' => array_values($taskUserList['partner']),
                ],
            ];
        }
        return $res;
    }

    /**
     * 增加待办任务成员
     * @param $data
     * @return bool
     * @throws Throwable
     */
    public function addMember($data)
    {
        $model = model(TaskMemberModel::class);
        $task = model(TaskModel::class)->find($data['task_id']);
        $taskStatus = json_decode($task['json'], true);
        // 获取任务提醒时间
        $taskClock = model(TaskClockModel::class)->field('time')->where(['task_id' => $data['task_id']])->select();
        $taskClockMap = array_column($taskClock, 'time');
        // 获取现有的执行人列表和参与人列表
        $taskMember = $model->where(['task_id' => $data['task_id']])->select();
        $executorMap = array_column($taskMember, null, 'user_id');
        $partnerMap = array_column($taskMember, null, 'partner');
        $addUsers = [];
        $updateUsers = [];

        if (!empty($data['executor'])) {
            foreach ($data['executor'] as $v) {
                if (!array_key_exists($v, $executorMap) && !array_key_exists($v, $partnerMap)) {
                    $addUsers = $this->getMember($addUsers, $v, $v, $data['task_id'], $taskStatus['task_status'], $v);
                } else if (array_key_exists($v, $partnerMap) && !array_key_exists($v, $executorMap)) {
                    // 如果之前是参与人，现在加入进执行人列表，就需要在原有的数据上进行更新
                    $updateUsers[$v]['user_id'] = $v;
                    $updateUsers[$v]['id'] = $partnerMap[$v]['id'];
                }
            }
        }
        if (!empty($data['partner'])) {
            foreach ($data['partner'] as $v) {
                if (!array_key_exists($v, $partnerMap) && !array_key_exists($v, $addUsers)) {
                    $addUsers = $this->getMember($addUsers, 0, $v, $data['task_id'], $taskStatus['task_status'], $v);
                }
            }
        }
        try {
            $model->startTrans();
            $res = [];
            if (!empty($updateUsers)) {
                // 更新用户加入执行人列表不需要系统通知
                $updateUsers = array_column($updateUsers, null);
                $model->saveAll($updateUsers);
            }
            if (!empty($addUsers)) {

                $res = $model->addAll(array_column($addUsers, null));
                $this->notifyTaskMemberUser($task, array_keys($addUsers));
                if (!empty($taskClockMap)) {
                    $this->notifyTaskMemberUser($task, array_keys($addUsers), $taskClockMap);
                }
            }
            $model->commit();
            return $res;
        } catch (Throwable $e) {
            $model->rollback();
            throw $e;
        }
    }

    /**
     * 转saas用户ID
     * @param $userId
     * @param bool $map
     * @return array
     */
    public function getSaasUserId($userId, $map = false)
    {
        if (empty($userId)) {
            return [];
        }
        $saasUser = model(UserModel::class)->field('id,union_id')->where(['union_id' => ['IN', $userId]])->select();
        if (!$map) {
            return array_column($saasUser, 'id');
        }
        return array_column($saasUser, 'id', 'union_id');
    }

    /**
     * 移除待办任务成员
     * @param $param
     * @return array|bool|int|string
     * @throws Exception
     */
    public function removeMember($param)
    {
        $res = [];
        $filter = $param['filter'];
        $model = model(TaskMemberModel::class);
        if ($filter['type'] == 'executor') {
            $res = $model->where(['task_id' => $filter['task_id'], 'user_id' => $filter['user_id']])->save(['user_id' => 0]);
        } else if ($filter['type'] == 'partner') {
            // 必须先从执行人列表中移除才能移除参与者列表
            $executor = $model->where(['task_id' => $filter['task_id'], 'partner' => $filter['user_id']])->find();
            if ($executor['user_id'] == 0) {
                // 如果参与者被移除，这条待办任务数据将没有任何作用，直接删除即可
                $res = $model->where(['id' => $executor['id']])->delete();
            } else {
                throw_strack_exception('remove executor information first', ErrorCode::DELETE_TASK_MEMBER_USER);
            }
        }
        return $res;
    }

    /**
     * 检查待办提醒时间
     * @param int $taskId
     * @return array
     * @throws Exception
     */
    public function checkMemberClock(int $taskId)
    {
        $taskMemberClockMap = [];
        $taskMemberUsersMap = [];
        $task = model(TaskModel::class)->find($taskId);
        $taskStatus = json_decode($task['json'], true);
        $statusService = StatusService::getInstance();
        $taskDefaultStatus = $statusService->getTaskDefaultStatus();
        // 只有任务在未完成的状态下才能有提醒，且只提醒任务还未完成的人
        if ($taskStatus['task_status'] == $taskDefaultStatus['id']) {
            $taskMember = model(TaskMemberModel::class)->where(['task_id' => $taskId, 'status' => $taskDefaultStatus['id']])->select();
            $taskMemberMap = array_column($taskMember, 'partner');
            $taskMemberUsers = model(UserModel::class)->field('union_id')->where(['id' => ['in', implode(',', $taskMemberMap)]])->select();
            $taskMemberClock = model(TaskClockModel::class)->where(['task_id' => $taskId, 'type' => 'to_do'])->select();
            $taskMemberUsersMap = array_column($taskMemberUsers, 'union_id');
            // 查找该任务下的所有成员是否在这个租户下，如果没有就不提醒
            $param['filter'] = [
                "tenant_user.tenant_id" => $task['tenant_id'],
                "user.id" => ['-in', $taskMemberUsersMap],
                "tenant_user.status" => 'active',
            ];
            $remoteUserData = teamones_request('teamones-im', 'tenant_user/select_tenant_user', [
                'param' => $param,
            ])['data'];
            if ($remoteUserData) {
                $tenantUser = [];
                foreach ($remoteUserData['rows'] as $key => $user) {
                    if (in_array($user['user']['id'], $tenantUser)) {
                        continue;
                    }
                    $tenantUser[$key] = $user['user']['id'];
                }
                $taskMemberUsersMap = array_values($tenantUser);
            } else {
                $taskMemberUsersMap = [];
            }
            $taskMemberClockMap = array_column($taskMemberClock, 'time');
        }
        return [
            'clock_time' => $taskMemberClockMap,
            'clock_users' => $taskMemberUsersMap
        ];
    }

    /**
     * 查找工单待办人员
     * @param int $taskWorkOrderId
     * @return array
     * @throws Exception
     */
    public function selectWorkOrderUser(int $taskWorkOrderId)
    {
        $res = [
            'selected' => [],
            'unselected' => []
        ];
        $taskWorkOrder = model(TaskWorkOrderModel::class)->field('task.project_id, task_work_order.created_by, task_work_order.receiver')->join('task on task_work_order.task_id = task.id')->where(['task_work_order.id' => $taskWorkOrderId])->find();
        if (empty($taskWorkOrder)) {
            throw new \think\Exception('task work order not found', ErrorCode::TASK_WORK_ORDER_NOT_EXIST);
        }
        $needRole = [
            TaskService::QA_CODE,
            'step_producer',
            TaskService::HEADMAN_CODE,
        ];
        // 获取TA角色的用户(后续会去除掉)
        $projectMember = model(ProjectMemberModel::class)
            ->where(['project_id' => $taskWorkOrder['project_id'], 'role_code' => ['IN', implode(',', $needRole)]])
            ->group('user_id')->select();
        $baseUserIdList = array_column($projectMember, 'user_id', 'user_id');

        $taUserList = UserService::getInstance()->getUserListByRole(['role_code' => 'technical_art']);
        $taUserIdList = array_column($taUserList, 'id', 'id');
        $baseUserIdList += $taUserIdList;
        $baseUserIdList[$taskWorkOrder['created_by']] = $taskWorkOrder['created_by'];
        $baseUserIdList[$taskWorkOrder['receiver']] = $taskWorkOrder['receiver'];
        // 查找已有的工单待办人员
        $taskWorkOrderUsers = model(TaskWorkOrderUserModel::class)->where(['work_order_id' => $taskWorkOrderId])->select();
        $taskWorkOrderUsersMap = array_column($taskWorkOrderUsers, null, 'user_id');
        $baseUserIdList += array_column($taskWorkOrderUsersMap, 'user_id', 'user_id');

        $users = model(UserModel::class)->field('id,name,avatar,union_id')->where(['id' => ['IN', implode(',', $baseUserIdList)]])->select();
        // 查找工单下的待办
        $taskIdList = model(TaskWorkOrderTaskListModel::class)
            ->where(['work_order_id' => $taskWorkOrderId])
            ->column('task_id');
        $executor = [];
        $partner = [];
        if ($taskIdList) {
            $taskMember = model(TaskMemberModel::class)->where(['task_id' => ['IN', $taskIdList]])->select();
            if ($taskMember) {
                $executor = array_column($taskMember, 'user_id');
                $partner = array_column($taskMember, 'partner');
            }
        }
        foreach ($users as $user) {
            if (array_key_exists($user['id'], $taskWorkOrderUsersMap)) {
                $user['is_deleted'] = false;
                $user['created'] = $taskWorkOrderUsersMap[$user['id']]['created'];
                if ($user['id'] == $taskWorkOrder['created_by']
                    || $user['id'] == $taskWorkOrder['receiver']
                    || in_array($user['id'], $executor)
                    || in_array($user['id'], $partner)) {
                    $user['is_deleted'] = true;
                    $user['is_create_role'] = $user['id'] == $taskWorkOrder['created_by'] || $user['id'] == $taskWorkOrder['receiver'];
                }
                $res['selected'][] = $user;
            } else {
                if (in_array($user['id'], $taUserIdList)) {
                    $user['role_code'] = 'technical_art';
                }
                $res['unselected'][] = $user;
            }
        }

        foreach ($res['selected'] as $key => $row) {
            $sort[$key] = $row['created'];
        }
        array_multisort($sort, SORT_ASC, $res['selected']);

        return $res;
    }

    /**
     * 分配工单待办成员
     * @param $data
     * @return array
     * @throws Exception|Throwable
     */
    public function allocationWorkOrderUser($data)
    {
        $add = [];
        $res = null;
        if (isset($data['user_id']) && $data['user_id']) {
            $data['user_id'] = $this->getSaasUserId($data['user_id']);
            $model = model(TaskWorkOrderUserModel::class);
            $taskWorkOrderUser = $model->where(['work_order_id' => $data['work_order_id']])->select();
            $taskWorkOrderUserIds = array_column($taskWorkOrderUser, null, 'user_id');
            foreach ($data['user_id'] as $key => $userId) {
                if (!array_key_exists($userId, $taskWorkOrderUserIds)) {
                    $add[$key]['user_id'] = $userId;
                    $add[$key]['work_order_id'] = $data['work_order_id'];
                    $add[$key]['created'] = time();
                } else {
                    unset($taskWorkOrderUserIds[$userId]);
                }
            }
            $add = array_values($add);
            $addedHookData = [
                'add' => $add,
                'work_order_id' => $data['work_order_id'],
                'join_type' => 'invite',
            ];
            $del = array_column($taskWorkOrderUserIds, 'id');
            $deletedHookData = [
                'del' => array_column($taskWorkOrderUserIds, 'user_id'),
                'work_order_id' => $data['work_order_id']
            ];
            $model->startTrans();
            try {
                if (!empty($add)) {
                    $res = $model->addAll($add);
                    Hook::listen('task_work_order_user_added', $addedHookData);
                }
                if (!empty($del)) {
                    $model->where(['id' => ['IN', $del]])->delete();
                    Hook::listen('task_work_order_user_deleted', $deletedHookData);
                }
                $model->commit();
            } catch (Throwable $e) {
                $model->rollback();
                throw $e;
            }
        } else if (isset($data['project_member']) && $data['project_member']) {
            $project = ProjectService::getInstance();
            $projectMemberData = [
                'project_id' => $data['project_id'],
            ];
            $projectMemberData['user_list'] = array_map(function ($item) {
                return [
                    'role_code' => 'technical_art',
                    'user_id' => $item,
                ];
            }, $data['project_member']);
            $res = $project->batchCreateProjectMemberMultiRole($projectMemberData);
        }
        return $res;
    }

    /**
     * 用户任务设置
     * @param $data
     * @param $userId
     * @return array|bool|null
     * @throws Throwable
     * @throws \think\Exception
     */
    public function userTaskSet($data, $userId)
    {
        try {
            $user = CommonService::instance("user");
            $data['id'] = $userId;
            return $user->update($data);
        } catch (Throwable $e) {
            throw $e;
        }
    }

    /**
     * 获取用户任务设置
     * @param $userId
     * @param $tenantId
     * @return array|bool
     * @throws \think\Exception
     */
    public function getUserTaskSet($userId, $tenantId)
    {
        $redisKey = "user_daily_todo_notify:" . "tenant_id-" . $tenantId . $userId . date("Ymd");
        $exist = Redis::getSet($redisKey, true);
        Redis::expire($redisKey, 86400);
        if (!$exist) {
            $user = model(UserModel::class)->find($userId);
            $statusService = StatusService::getInstance();
            $taskStatus = $statusService->getList([], "*");
            $taskStatusMap = array_column($taskStatus, 'id', 'code');
            $model = model(TaskMemberModel::class);
            $joinModel = "task ON task_member.task_id = task.id";
            $entity_module_id = module_by_code('todo')['id'];
            $count['to_do'] = $model->where(['task_member.user_id' => $userId, 'task_member.status' => $taskStatusMap['not_started'], 'task.entity_module_id' => $entity_module_id, 'task.step_type' => 'to_do', 'task.tenant_id' => $tenantId])->join($joinModel)->count();
            $count['work_order_to_do'] = $model->where(['task_member.user_id' => $userId, 'task_member.status' => $taskStatusMap['not_started'], 'task.entity_module_id' => $entity_module_id, 'task.step_type' => 'work_order_to_do', 'task.tenant_id' => $tenantId])->join($joinModel)->count();
            if (!empty($count) && $count['to_do'] > 0 || $count['work_order_to_do'] > 0) {
                $hookData = [
                    'type' => 'daily_task_notification',
                    'data' => [
                        'user' => $user,
                        'count' => $count,
                    ]
                ];
                Hook::listen('sign_in_after', $hookData);
                return true;
            }
        }
        return [];
    }

    /**
     * 遍历获取待办成员信息
     * @param array $member
     * @param $user_id
     * @param $partner
     * @param $task_id
     * @param $status
     * @param $key
     * @param int $starter
     * @return array
     */
    private function getMember(array $member, $user_id, $partner, $task_id, $status, $key, $starter = 0): array
    {
        if (empty($member[$key]['partner'])) {
            $member[$key]['partner'] = $partner;
        }
        if (empty($member[$key]['user_id'])) {
            $member[$key]['user_id'] = $user_id;
        }
        if (empty($member[$key]['starter'])) {
            $member[$key]['starter'] = $starter;
        }
        $member[$key]['task_id'] = $task_id;
        $member[$key]['created'] = time();
        $member[$key]['status'] = $status;
        return $member;
    }

    /**
     * 待办任务提醒消息
     * @param array $task
     * @param array $taskUsers
     * @param array $taskClock
     * @return array
     * @throws \Exception
     */
    private function notifyTaskMemberUser(array $task, array $taskUsers, array $taskClock = [])
    {
        if (empty($taskUsers)) {
            return [];
        }
        $skipTaskType = ['standard_make_to_do'];
        if (in_array($task['step_type'], $skipTaskType)) {
            return [];
        }
        $userIds = array_merge($taskUsers, [$task['created_by']]);
        $users = model(UserModel::class)->field('id,union_id,name')->where(['id' => ['in', $userIds]])->select();

        $creatorName = "";
        $userUnionId = [];
        foreach ($users as $userItem) {
            if (in_array($userItem['id'], $taskUsers)) {
                $userUnionId[] = $userItem['union_id'];
            }
            if ($task['created_by'] == $userItem['id']) {
                $creatorName = $userItem['name'];
            }
        }

        $templateId = $this->getTaskMemberNotifyTemplateId('message_notify_template_config', 'notify_task_member_template_id');
        $messageParam = [
            'first' => '待办任务提醒',
            'task_name' => $task['name'],
            'task_content' => $task['description'],
            'creator_name' => $creatorName,
            'send_at' => date('Y-m-d H:i:s', time()),
            'remark' => '请及时查看',
            'task_id' => $task['id'],
        ];

        $msg = [
            "param" => $messageParam,
            'template_id' => $templateId,
            'content_type' => 'card_message',
            'notice_type' => 'message_task',
            'is_popup' => 1,
            'message_key' => 'notify_task_member'
        ];
        if (empty($taskClock)) {
            foreach ($userUnionId as $user) {
                $msg['receiver'] = $user;
                Client::send("send_notify_message_v2", build_queue_data_with_xu($msg));
            }
        } else {
            foreach ($taskClock as $clock) {
                $delay = $clock - time();
                if ($delay > 0) {
                    $msg['task_id'] = $task['id'];
                    $msg['clock_time'] = $clock;
                    $msg['x_user_info'] = request()->getXUserInfo();
                    Client::send("task_member_clock", build_queue_data_with_xu($msg), $delay);
                }
            }
        }
    }

    /**
     * 获取任务待办消息模板
     * @return int
     * @throws Exception
     */
    public function getTaskMemberNotifyTemplateId($optionName, $templateName)
    {
        $messageTemplateId = OptionsService::getInstance()->getOptionsConfigItemData($optionName, $templateName);
        return (int)$messageTemplateId;
    }

    /**
     * 根据任务ID分配成员
     * @param $taskId
     * @param array $executorList
     * @param array $partnerList
     * @param int $status
     * @return array|array[]
     */
    private function allocationMember($taskId, $executorList, $partnerList, $startManId, int $status)
    {
        //如果执行人和参与人都不存在
        if (!isset($executorList) && !isset($partnerList)) {
            return [];
        }

        $taskMemberList = model(TaskMemberModel::class)->where(['task_id' => $taskId])->select();

        if (isset($executorList)) {
            $executorUserList = model(UserModel::class)->field('id')->where(['union_id' => ['IN', $executorList]])->select();
            $executorList = array_column($executorUserList, 'id', 'id');
        } else {
            //过滤掉空的执行人
            $executorList = array_filter(array_column($taskMemberList, 'user_id', 'user_id'));
        }


        //判定是否给予了参与人
        if (isset($partnerList)) {
            $partnerUserList = model(UserModel::class)->field('id')->where(['union_id' => ['IN', $partnerList]])->select();
            $partnerList = array_column($partnerUserList, 'id', 'id');
        } else {
            $partnerList = array_column($taskMemberList, 'partner', 'partner');
        }

        $executorMap = [];
        $partnerMap = [];
        $needDelete = [];
        $needDeleteIds = [];
        $needUpdateTaskMember = [];
        $res = [
            "need_delete" => [],
            "need_add" => [],
            "need_update" => [],
        ];
        foreach ($taskMemberList as $taskMember) {
            //判定是否是执行人

            $isExecutor = $taskMember['user_id'] > 0;
            $isPartner = $taskMember['partner'] > 0;
            $isStartMan = $taskMember['start_man_id'] > 0;
            //更新逻辑判定

            $isNoExistExecutor = $isNoExistPartner = $isNoExistStartMan = false;

            $currentUpdateData = [];
            if ($isExecutor) {
                //如果找不到，则置空
                if (!isset($executorList[$taskMember['user_id']])) {
                    $isNoExistExecutor = true;
                    $currentUpdateData['user_id'] = $taskMember['user_id'] = 0;
                } else {
                    //如果再次执行人存在则判定, todo  其中的角色id 与 其中  环节id比较
                    //该执行人与参与人都不需要在添加
                    unset($executorList[$taskMember['user_id']], $partnerList[$taskMember['user_id']]);

                }

                if (!isset($partnerList[$taskMember['user_id']])) {
                    $currentUpdateData['partner'] = $taskMember['partner'] = 0;
                }
            }

            if ($isPartner) {
                //参与人不存在自己 并且 自己不是执行人
                if (!isset($partnerList[$taskMember['user_id']]) && !isset($executorList[$taskMember['user_id']])) {
                    $isNoExistPartner = true;
                    $currentUpdateData['partner'] = $taskMember['partner'] = 0;
                }

                //如果参与人存在 则该参与人不需要再添加
                if (isset($partnerList[$taskMember['user_id']])) {
                    unset($partnerList[$taskMember['user_id']]);
                }

                //如果之前不是执行人，但现在是执行人
                if ($taskMember['user_id'] < 0 && isset($executorList[$taskMember['user_id']])) {
                    $currentUpdateData['user_id'] = $executorList[$taskMember['user_id']];
                }
            }

            //如果之前发起人
            if ($isStartMan) {
                if ($taskMember['start_man_id'] != $startManId) {
                    $isNoExistStartMan = true;
                    $currentUpdateData['start_man_id'] = 0;
                } else {
                    //如果之前不是，但现在是否是发起人
                    if ($taskMember['start_man_id'] = $startManId) {
                        $currentUpdateData['user_id'] = $startManId;
                    }
                }
            }

            if ($isNoExistExecutor && $isNoExistPartner && $isNoExistStartMan) {
                continue;
            }

            if (!empty($currentUpdateData)) {
                $currentUpdateData['id'] = $taskMember['id'];
            }
        }

        return $res;
    }

    /**
     * 增加工单用户,同步到IM
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function taskWorkOrderUserAddIm($userId, $workOrderId)
    {
        // 转换Im UserId
        $saasUser = model(UserModel::class)->field('id,union_id')->where(['id' => ['IN', $userId]])->select();
        $unionId = array_column($saasUser, 'union_id');
        $workData = model(TaskWorkOrderModel::class)->where(['id' => $workOrderId])->find();
        $receiver = [];
        foreach ($unionId as $value) {
            $receiver[] = ['type' => 'user', 'id' => $value];
        }
        if (!empty($workData['chat_global_id'])) {
            $requestData = [
                "data" => [
                    'receiver' => $receiver,
                    'chat_global_id' => $workData['chat_global_id']
                ]
            ];
            return teamones_request('teamones-im', 'chat_user/invite_users_or_department', $requestData);
        }
    }

    /**
     * 删除工单用户同步到IM
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function taskWorkOrderDeleted($userId, $workOrderId)
    {
        // 转换Im UserId
        $saasUser = model(UserModel::class)->field('id,union_id')->where(['id' => ['IN', $userId]])->select();
        $unionId = array_column($saasUser, 'union_id');
        $workData = model(TaskWorkOrderModel::class)->where(['id' => $workOrderId])->find();
        $chatGlobalId = $workData['chat_global_id'];
        $requestData = [
            "param" => [
                "filter" => [
                    'user_id' => ['-in', $unionId],
                    'chat_global_id' => $chatGlobalId,
                ],
            ],
        ];
        return teamones_request('teamones-im', 'chat_user/delete_user', $requestData);
    }

    /**
     * 清除任务提醒
     * @param $data
     * @return void
     */
    private function deleteTaskClock($data)
    {
        $taskClock = model(TaskClockModel::class);
        $taskClockData = $taskClock->where(['task_id' => $data['id'], 'type' => 'to_do'])->select();
        if ($taskClockData) {
            $taskClockDataMap = array_column($taskClockData, 'id');
            $taskClock->where(['id' => ['IN', $taskClockDataMap]])->delete();
        }
    }

    /**
     * 待办操作发送消息
     * @param $data
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    private function pushMessage($data)
    {
        $requestData = [
            "data" => [
                'receives' => $data['im_user_ids'],
                'content_type' => $data['content_type'],
                'global_id' => $data['task_order_data']['chat_global_id'],
                'executor_ids' => $data['executor'] ?? [],
                'content_extra_data' => ['work_order_id' => $data['task_order_data']['id'], 'work_order_name' => $data['task']['name']]
            ],
        ];
        return teamones_request('teamones-im', 'message/push_work_order_chat_message', $requestData);
    }

    /**
     * 通知工单待办成员发生变化
     * @param $task
     * @param array $allocationExecutor
     * @return void
     */
    private function notifyTaskWorkOrderTodoExecutorChanged($task, array $allocationExecutor)
    {
        $taskWorkOrderId = $task['task_work_order_id'] ?? 0;
        if ($taskWorkOrderId <= 0) {
            return;
        }
        // 获取工单数据和工单所有用户成员
        $taskOrderData = model(TaskWorkOrderModel::class)->find($taskWorkOrderId);
        $workOrderUserList = model(TaskWorkOrderUserModel::class)
            ->field('user_id')
            ->where(['work_order_id' => $taskWorkOrderId])
            ->select();
        $saasUserIds = array_column($workOrderUserList, 'user_id');
        $imUserIds = model(UserModel::class)
            ->where(['id' => ['IN', $saasUserIds]])
            ->column('union_id');

        // 新增或更新执行人发送提醒
        if ($allocationExecutor['add']) {
            $addExecutor = model(UserModel::class)
                ->where(['id' => ['IN', implode(',', $allocationExecutor['add'])]])
                ->column('union_id');
            $pushMessage['content_type'] = "add_work_order_executor";
            $pushMessage['im_user_ids'] = $imUserIds;
            $pushMessage['executor'] = $addExecutor;
            $pushMessage['task'] = $task;
            $pushMessage['task_order_data'] = $taskOrderData;
            $this->pushMessage($pushMessage);
        }
        // 删除执行人发送提醒
        if ($allocationExecutor['del']) {
            $delExecutor = model(UserModel::class)
                ->where(['id' => ['IN', implode(',', $allocationExecutor['del'])]])
                ->column('union_id');
            $pushMessage['content_type'] = "del_work_order_executor";
            $pushMessage['im_user_ids'] = $imUserIds;
            $pushMessage['executor'] = $delExecutor;
            $pushMessage['task'] = $task;
            $pushMessage['task_order_data'] = $taskOrderData;
            $this->pushMessage($pushMessage);
        }
    }

    /**
     * 删除待办
     * @param $taskTodoId
     * @return false|int|mixed|string
     * @throws Throwable
     * @throws \think\Exception
     */
    public function delete($taskTodoIdFilter)
    {
        $res = 0;

        $taskList = model(TaskModel::class)->where(['id' => $taskTodoIdFilter, 'entity_module_id' => module_by_code('todo')['id']])->field("id,project_id")->select();
        if (empty($taskList)) {
            return $res;
        }
        $taskIds = array_column($taskList, "id");
        // 查询主待办下的子待办(包括事项衍生出来的模板待办任务)
        $subTodoList = DismantleTaskService::getInstance()->getDismantleTaskIds($taskIds, ['IN', [TaskRelationModel::RELATION_TYPE_SUB_TODO, TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO]]);
        if (!empty($subTodoList)) {
            $subTodoIds = array_column($subTodoList, 'id');
            $taskIds = array_merge($taskIds, $subTodoIds);
        }
        $this->taskMemberModel->startTrans();
        try {
            // 删除主待办任务
            $res = model(TaskModel::class)->where(['id' => ["IN", $taskIds]])->delete();
            // 删除待办成员数据
            $this->taskMemberModel->where(['task_id' => ["IN", $taskIds]])->delete();
            // 删除待办成员关联表
            $this->TaskMemberRelationModel->where(['task_id' => ["IN", $taskIds]])->delete();
            // 删除关联 tag
            $trTagIds = $this->taskRelationTag->where(['task_id' => ['IN', $taskIds]])->column('id');
            if (!empty($trTagIds)) {
                $this->taskRelationTag->where(['id' => ['IN', $trTagIds]])->delete();
            }
            // 删除主待办与子待办关联
            foreach ($taskList as $taskItem) {
                $taskId = $taskItem['id'];
                $projectId = $taskItem['project_id'] ?? 0;
                $this->taskRelation->setSuffix(sprintf('_project_%d', $projectId))->where(['source_task_id' => $taskId])->delete();
            }
            $this->taskMemberModel->commit();
        } catch (Throwable $e) {
            $this->taskMemberModel->rollback();
            throw $e;
        }
        return $res;
    }

    /**
     * 查询概念的贴图工序任务列表
     * @param $designIdList
     * @return array
     * @throws \think\Exception
     */
    private function getDesignTexStepTaskList($designIdList)
    {
        $res = [];
        if (empty($designIdList)) {
            return $res;
        }
        $designFilter = ['id' => ['IN', $designIdList]];
        $designList = model(EntityModel::class)->where($designFilter)->field('id,project_id,code')->select();
        if (empty($designList)) {
            return $res;
        }
        $entityListFilter = ['_logic' => 'or'];
        foreach ($designList as $design) {
            $entityListFilter[] = [
                'entity.project_id' => $design['project_id'],
                'entity.code' => $design['code'],
            ];
        }
        $entityList = model(EntityModel::class)
            ->join('module m on m.id = entity.module_id')
            ->where(['m.id' => ['IN', [module_by_code('asset')['id'], module_by_code('level')['id']]], $entityListFilter])
            ->field('entity.id,' . "json_unquote(json_extract(entity.json,concat('$.',m.code,'_design'))) as design_id")->select();
        if (empty($entityList)) {
            return $res;
        }
        $designEntityTexStepTaskRelationMap = array_column($entityList, 'design_id', 'id');
        $entityIdList = array_column($entityList, 'id');
        $entityTexStepTaskListFilter = [
            'step.code' => ['IN', OptionsService::getInstance()->getTexStepCode()],
            'task.entity_id' => ['IN', $entityIdList],
        ];
        $entityTexStepTaskList = model(TaskModel::class)->join('step on step.id = task.step_id')->where($entityTexStepTaskListFilter)->field('task.*')->select();
        foreach ($entityTexStepTaskList as $entityTexStepTask) {
            CommonService::getFormatAttrData(model(TaskModel::class), $entityTexStepTask);
            $designId = $designEntityTexStepTaskRelationMap[$entityTexStepTask['entity_id']] ?? 0;
            $res[$designId] = $entityTexStepTask;
        }
        return $res;
    }

    /**
     * 分配工单待办成员 操作新增互斥🔒
     * @param $data
     * @return array
     * @throws Exception|Throwable
     */
    public function allocationWorkOrderUserV2($data)
    {
        $mutex = new PHPRedisMutex([Redis::connection()->client()], "allocationWorkOrderUserV2-{$data['work_order_id']}", 5);
        return $mutex->synchronized(function () use ($data) {
            $res = [];
            $userIdList = array_column($data['user_list'], 'id');
            $userIdMap = $this->getSaasUserId($userIdList, true);
            $workOrderData = model(TaskWorkOrderModel::class)->find($data['work_order_id']);
            $taskWorkOrderUserList = model(TaskWorkOrderUserModel::class)->where(['work_order_id' => $data['work_order_id']])->select();
            $taskWorkOrderUserList = array_column($taskWorkOrderUserList, null, 'user_id');
            $projectMemberDataUserList = [

            ];
            $add = [];
            $created = time();
            foreach ($data['user_list'] as &$user) {
                $user['id'] = $currentUserId = $userIdMap[$user['id']] ?? 0;
                if ($currentUserId === 0) {
                    continue;
                }
                // 新加入的成员  添加到项目成员中去
                if (!empty($user['role_code'])) {
                    $projectMemberDataUserList[] = [
                        'user_id' => $currentUserId,
                        'role_code' => $user['role_code'],
                    ];
                }

                // 判断成员的去留
                if (!array_key_exists($currentUserId, $taskWorkOrderUserList)) {
                    $add[] = [
                        'user_id' => $currentUserId,
                        'work_order_id' => $data['work_order_id'],
                        'created' => $created,
                    ];
                } else {
                    unset($taskWorkOrderUserList[$currentUserId]);
                }
            }
            $addedHookData = [
                'add' => $add,
                'work_order_id' => $data['work_order_id'],
                'join_type' => 'invite',
            ];
            $del = array_column($taskWorkOrderUserList, 'id');
            $deletedHookData = [
                'del' => array_column($taskWorkOrderUserList, 'user_id'),
                'work_order_id' => $data['work_order_id']
            ];
            model(TaskWorkOrderUserModel::class)->startTrans();
            try {
                if (!empty($add)) {
                    $res[] = model(TaskWorkOrderUserModel::class)->addAll($add);
                    Hook::listen('task_work_order_user_added', $addedHookData);
                }
                if (!empty($del)) {
                    model(TaskWorkOrderUserModel::class)->where(['id' => ['IN', $del]])->delete();
                    Hook::listen('task_work_order_user_deleted', $deletedHookData);
                }
                if (!empty($projectMemberDataUserList)) {
                    $res[] = ProjectService::getInstance()->batchCreateProjectMemberV2($workOrderData['project_id'], ProjectMemberModel::PRODUCTION_TYPE, $projectMemberDataUserList);
                }
                model(TaskWorkOrderUserModel::class)->commit();
            } catch (Throwable $e) {
                model(TaskWorkOrderUserModel::class)->rollback();
                throw $e;
            }
            return $res;
        });
    }

    /**
     * 删除待办
     * @param $filter
     * @param $userId
     * @return false|int
     * @throws Throwable
     * @throws \think\Exception
     */
    public function deleteTaskMember($filter, $userId)
    {
        $task = model(TaskModel::class)->find($filter['id']);
        if (empty($task)) {
            throw_strack_exception('task id not found', ErrorCode::TASK_NOT_FOUND);
        }
        $task['json'] = json_decode($task['json'], true);
//        if ($task['created_by'] != $userId) {
//            throw_strack_exception('You do not have permission', ErrorCode::TASK_MEMBER_DELETE_ROLE);
//        }
//        if ($task['json']['task_status'] != 3) {
//            throw_strack_exception('Must be canceled to delete', ErrorCode::TASK_MEMBER_DELETE_BEFORE_STATUS);
//        }

        // 有排期的不能删除
        $planData = model(PlanModel::class)->where(['task_id' => $task['id']])->field('id')->find();
        if (!empty($planData)) {
            throw_strack_exception('plan task Can\'t delete', ErrorCode::TASK_MEMBER_DELETE_BEFORE_STATUS);
        }

        return $this->delete($filter['id']);
    }

    /**
     * 代办任务关联标签
     * @param $task
     * @param $tag
     * @return array
     * @throws \Exception
     */
    public function toDoTaskRelateTag($task, $tag)
    {
        $tag = array_map(function ($tagItem) use ($task) {
            $tagItem['task_id'] = $task['id'];
            $tagItem['tenant_id'] = $task['tenant_id'];
            $tagItem['created_by'] = $task['created_by'];
            $tagItem['project_id'] = $task['project_id'];
            $tagItem['created'] = $tagItem['updated'] = time();
            //给 key 排序
            ksort($tagItem);
            return $tagItem;
        }, $tag);

        $tag = array_values($tag);
        model(TaskRelationTagModel::class)->addAll($tag);
        return $tag;
    }

    /**
     * 判定是否有数据更改
     * @param $taskData
     * @return bool
     */
    public function isExistTaskChange($taskData)
    {
        // 是否存在id之外的数值,存在则修改
        $isExistChange = false;
        foreach ($taskData as $taskDataIndex => $taskDataItem) {
            if ($isExistChange) {
                break;
            }
            if ($taskDataIndex !== 'id') {
                $isExistChange = true;
            }
        }
        return $isExistChange;
    }

    /**
     * 按类型统计任务的关联任务
     * @param $param
     * @return array
     */
    public function taskRelationCountByRelationType($param)
    {
        $res = [];
        $filter = $param['filter'] ?? [];
        $projectId = $param['project_id'] ?? 0;
        if (empty($filter)) {
            return $res;
        }
        $taskRelationCount = model(TaskRelationModel::class)
            ->setSuffix(sprintf('_project_%d', $projectId))
            ->alias('task_relation')
            ->where($filter)
            ->field("source_task_id as task_id, relation_type, count(id) as related_task_count")
            ->group("source_task_id, relation_type")
            ->select();

        if (empty($taskRelationCount)) {
            return $res;
        }
        $taskRelationCountMap = [];
        foreach ($taskRelationCount as $item) {
            $taskRelationCountMap[$item['task_id']][$item['relation_type']] = $item['related_task_count'];
        }
        foreach ($taskRelationCountMap as $taskId => $item) {
            $res[] = [
                'task_id' => $taskId,
                'relation_group_count' => $item
            ];
        }
        return $res;
    }

    /**
     * 查找任务关联项
     * @param $param
     * @return array
     * @throws \think\Exception
     */
    public function taskRelationList($param)
    {
        $id = $param['filter']['id']; //拿到任务id
        $res = [];
        $taskQueryFields = [
            "task.id",
            "task.entity_id",
            "task.name",
            "task.description",
            "task.plan_start_time",
            "task.plan_end_time",
            "user.name as created_name",
            "user.avatar",
            "project.name as project_name",
            "project.id as project_id",
            "plan.scope as scope",
            "plan.type as type"
        ];
        $task = model(TaskModel::class) //根据任务id查出task,user,project,plan表中的信息
        ->field($taskQueryFields)
            ->join('user ON task.created_by = user.id')
            ->join("project ON task.project_id = project.id", 'LEFT')
            ->join("plan ON task.id = plan.task_id", 'LEFT')
            ->where(['task.id' => $id])
            ->find();
        if (empty($task)) {
            return [];
        }
        $res['task'] = $task;
        $taskTagRelationResult = TaskRelationTagService::getInstance()->getTaskRelationListDetail($id);
        $res['relate_tag'] = $taskTagRelationResult['result'];//关联项

        if ($res['task']['scope'] == PlanModel::SCOPE_SINGLE) {//判断是单集还是全局
            $res['ep_name'] = $taskTagRelationResult['episode'][0]['code'] ?? ''; //单集就拿出id跟name
            $res['ep_id'] = $taskTagRelationResult['episode'][0]['id'] ?? 0;
        } else {
            if (!empty($taskTagRelationResult["episode"])) {//判断有没有实体数据
                $res['ep_count'] = count($taskTagRelationResult['episode']) . "集";//计算实体数据有多少条
            }
            $res['ep_name'] = PlanModel::SCOPE_GLOBAL; //全局就显示全局
            $res['ep_id'] = PlanModel::SCOPE_GLOBAL;
        }
        // 查询执行者列表并统计个数
        $taskMemberList = model(TaskMemberModel::class)->field('id,user_id,partner,status')->where(['task_id' => $id])->select();//根据任务id查出task_member待办任务表中的信息
        $executorIds = array_column($taskMemberList, 'user_id'); //拿到待办任务中有几个执行者的id
        $executor = model(UserModel::class)->field('id,name,avatar')->where(['id' => ['IN', implode(',', $executorIds)]])->select();//跟据待办任务表中查出的执行者的id去用户表中查出名字跟id
        $res['executor']['user'] = $executor;//执行人
        $res['executor']['total'] = count($executor);//统计执行者个数
        // 查询参与者列表并统计个数
        $partnerIds = array_column($taskMemberList, 'partner');//拿到参与者的id
        $partners = model(UserModel::class)->field('id,name,avatar')->where(['id' => ['IN', implode(',', $partnerIds)]])->select();
        $res['partners']['user'] = $partners;//执行人
        $res['partners']['total'] = count($partners);//统计执行者个数
        return $res;
    }


    /**
     * 获取任务成员详细列表
     * @param $taskIds
     * @return array|false|mixed|string
     */
    public function getTaskMemberUserInfoList($taskIds)
    {
        $taskMemberList = model(TaskMemberModel::class)
            ->where(['task_id' => ['IN', $taskIds]])
            ->where(['user_id' => ['GT', 0]])
            ->select();

        if (empty($taskMemberList)) {
            return $taskMemberList;
        }
        $userIdList = [];
        foreach ($taskMemberList as $taskMember) {
            $userIdList[$taskMember['user_id']] = $taskMember['user_id'];
        }


        $userList = model(UserModel::class)->where(['id' => ["IN", array_values($userIdList)]])->field('id,name,avatar')->select();
        $userList = array_column($userList, null, 'id');

        foreach ($taskMemberList as $taskMemberIndex => $taskMember) {
            $taskMember['user_info'] = $userList[$taskMember['user_id']] ?? null;
            $taskMemberList[$taskMemberIndex] = $taskMember;
        }

        return array_group_by($taskMemberList, 'task_id');
    }

    /**
     * 批量创建待办
     * @param $data
     * @return array|bool
     */
    public function batchCreate($data)
    {
        if (empty($data)) {
            return [];
        }
        $tmpTitleList = [];
        // 去除重复标题的数据
        $saveData = [];
        foreach ($data as $item) {
            if (empty($item['task']['name']) || in_array($item['task']['name'], $tmpTitleList)) {
                continue;
            }
            $tmpTitleList[] = $item['task']['name'];
            $saveData[] = $item;
        }
        if (empty($saveData)) {
            return [];
        }
        foreach ($saveData as $item) {
            Client::send('task_member_batch_create', build_queue_data_with_xu($item));
        }
        return true;
    }

    /**
     * 更新子待办任务状态
     * @param $data
     * @param $taskStatus
     * @return void
     */
    public function updateSubTodoStatus($data, $taskStatus)
    {


        $taskFinalStatus = StatusService::getInstance()->getTaskDoneStatus(); // 已完成
        $taskClosedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus(); // 已取消
        $taskNotStarted = StatusService::getInstance()->getTaskDefaultStatus(); // 未开始
        if (!in_array($taskStatus, [$taskFinalStatus['id'], $taskClosedStatus['id'], $taskNotStarted['id']])) {
            return;
        }
        $projectId = $data['project_id'] ?? 0;
        // 模板待办,已完成不同步衍生任务
        $isTemplateTodo = model(TaskRelationModel::class)
            ->setSuffix(sprintf('_project_%d', $projectId))
            ->alias('task_relation')
            ->where([
                'source_task_id' => $data['id'], 'relation_type' => TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO
            ])->find();
        if (!empty($isTemplateTodo) && $taskStatus == $taskFinalStatus['id']) {
            return;
        }

        // 查询主待办下面的子待办
        $subTodoList = DismantleTaskService::getInstance()->getDismantleTaskIds([$data['id']], ['IN', [TaskRelationModel::RELATION_TYPE_SUB_TODO, TaskRelationModel::RELATION_TYPE_TEMPLATE_TODO]]);
        if (empty($subTodoList)) {
            return;
        }
        // 同步更改子待办状态
        try {
            $subTaskIds = [];
            $taskUpdateData = [];
            $taskMemberData = [];
            foreach ($subTodoList as $task) {
                $taskUpdateData[] = [
                    'id' => $task['id'],
                    'task_status' => $taskStatus
                ];
                $subTaskIds[] = $task['id'];
            }
            $taskMemberList = model(TaskMemberModel::class)->where(['task_id' => ['IN', $subTaskIds]])->field('id')->select();
            foreach ($taskMemberList as $item) {
                $taskMemberData[] = [
                    'id' => $item['id'],
                    'status' => $taskStatus
                ];
            }
            // 更新待办状态
            CommonService::instance('task')->commonBatchUpdate($taskUpdateData, module_by_code('task'), false);
            // 更新子待办成员状态
            CommonService::instance('task_member')->commonBatchUpdate($taskMemberData, module_by_code('task_member'), false);
        } catch (\Throwable $e) {
            throw_strack_exception('update sub todo fail', ErrorCode::UPDATE_SUB_TODO_STATUS_ERROR);
        }
    }

    /**
     * 处理成员数据合并数据
     * @param $data
     * @return array[]
     */
    public function dealTaskMemberDataMerge($data)
    {
        $taskMemberData = [];
        $taskMemberRelation = [];

        $newDataKey = ['executor_list', 'starter_list', 'partner_list'];
        $oldDataKey = ['executor', 'partner'];
        $dataKey = array_merge($newDataKey, $oldDataKey);

        $memberRoleMap = [
            'executor_list' => 'executor',
            'starter_list' => 'starter',
            'partner_list' => 'partner',
            'executor' => 'executor',
            'starter' => 'starter',
            'partner' => 'partner'
        ];
        //循环获取union_id
        $unionIds = [];
        foreach ($dataKey as $dataKeyItem) {

            if (!isset($data[$dataKeyItem])) {
                continue;
            }

            $executorList = $data[$dataKeyItem];
            foreach ($executorList as $executorItem) {
                if (empty($executorItem)) {
                    continue;
                }

                if (in_array($dataKeyItem, $newDataKey)) {
                    if (empty($executorItem['user_list'])) {
                        continue;
                    }

                    $unionIds = array_merge($unionIds, array_column($executorItem['user_list'], 'user_id'));
                } else {
                    $unionIds[] = $executorItem;
                }

            }
        }
        $unionIds = array_unique($unionIds);


        if (empty($unionIds)) {
            return ['task_member_data' => [], 'task_member_relation' => []];
        }

        $userList = model(UserModel::class)->where(["union_id" => ["IN", $unionIds]])->field("id,union_id")->select();
        $userMap = array_column($userList, 'id', 'union_id');

        $startUserIds = [];
        foreach ($dataKey as $dataKeyItem) {

            if (!isset($data[$dataKeyItem])) {
                continue;
            }

            $executorList = $data[$dataKeyItem];
            foreach ($executorList as $executorItem) {
                if (empty($executorItem)) {
                    continue;
                }

                if (in_array($dataKeyItem, $newDataKey)) {
                    if (empty($executorItem['user_list'])) {
                        continue;
                    }
                    $ids = $executorItem['id']; // 前端统一传数组

                    foreach ($executorItem['user_list'] as $userItem) {
                        if (empty($userItem['user_id'])) {
                            continue;
                        }

                        if (!isset($userMap[$userItem['user_id']])) {
                            continue;
                        }

                        //user_id转换
                        $currentUserId = $userMap[$userItem['user_id']];

                        if (!isset($taskMemberData[$currentUserId])) {
                            $taskMemberData[$currentUserId] = [
                                'user_id' => 0,
                                'partner' => 0,
                                'starter' => 0,
                            ];
                        }
                        //执行人,发起人,参与人 填补
                        if ($dataKeyItem == "starter_list") {
                            $startUserIds[$currentUserId] = $currentUserId;
                            if (count($startUserIds) > 1) { //发起人限制只会有一个
                                throw new LogicException("starter no more than one");
                            }
                            $taskMemberData[$currentUserId]['starter'] = $currentUserId;
                        } elseif ($dataKeyItem == "executor_list") {
                            $taskMemberData[$currentUserId]['user_id'] = $taskMemberData[$currentUserId]['partner'] = $currentUserId;
                        } else {
                            $taskMemberData[$currentUserId]['partner'] = $currentUserId;
                        }

                        //关联暂时混在一起,不区分发起人,执行人,参与人的关联
                        foreach ($ids as $id) {
                            $taskMemberRelationKey = join("-", [$executorItem['type'], $id, $userItem['department_id']]);
                            if (!isset($taskMemberRelation[$currentUserId])) {
                                $taskMemberRelation[$currentUserId] = [$taskMemberRelationKey => [
                                    'user_id' => $currentUserId,
                                    'link_module_code' => $executorItem['type'],
                                    'link_id' => $id,
                                    'department_id' => $userItem['department_id'],
                                    'member_role' => $memberRoleMap[$dataKeyItem] ?? '',
                                ]];
                            } elseif (!isset($taskMemberRelation[$currentUserId][$taskMemberRelationKey])) {
                                $taskMemberRelation[$currentUserId][$taskMemberRelationKey] = [
                                    'user_id' => $currentUserId,
                                    'link_module_code' => $executorItem['type'],
                                    'link_id' => $id,
                                    'department_id' => $userItem['department_id'],
                                    'member_role' => $memberRoleMap[$dataKeyItem] ?? '',
                                ];
                            }
                        }
                    }
                } else {
                    if (!isset($userMap[$executorItem])) {
                        continue;
                    }
                    //user_id转换
                    $currentUserId = $userMap[$executorItem];
                    if (!isset($taskMemberData[$currentUserId])) {
                        $taskMemberData[$currentUserId] = [
                            'user_id' => 0,
                            'partner' => 0,
                            'starter' => 0,
                        ];
                    }
                    if ($dataKeyItem == "executor") {
                        $taskMemberData[$currentUserId]['user_id'] = $taskMemberData[$currentUserId]['partner'] = $currentUserId;
                    } else {
                        $taskMemberData[$currentUserId]['partner'] = $currentUserId;
                    }
                }
            }
        }

        return ['task_member_data' => $taskMemberData, 'task_member_relation' => $taskMemberRelation];
    }

    /**
     * 更新成员数据
     * @param $taskMemberData
     * @param $newTaskMemberRelationMap
     * @param $taskId
     * @param $taskStatus
     * @param $data
     * @return array
     */
    public function getUpdateMemberData($taskMemberData, $newTaskMemberRelationMap, $taskId, $taskStatus, $data)
    {
        $taskMemberList = model(TaskMemberModel::class)->where(['task_id' => $taskId])->select();

        $taskMemberRelationList = model(TaskMemberRelationModel::class)->where(['task_id' => $taskId])->select();
        $taskMemberRelationMap = array_group_by($taskMemberRelationList, 'user_id');

        $isExecutor = isset($data['executor_list']) || isset($data['executor']);
        $isPartner = isset($data['partner_list']) || isset($data['partner']);
        $isStarter = isset($data['starter_list']);
        $currentTime = time();

        $isMemberDataExist = ['user_id' => $isExecutor, 'partner' => $isPartner, 'starter' => $isStarter];
        $deleteIds = [];
        $updateTaskMemberData = [];
        $deleteRelationIds = [];
        $taskMemberNeedAddRelationData = [];
        $needAddExecutor = [];
        $needDeleteExecutor = [];
        foreach ($taskMemberList as $taskMemberItem) {
            if ($taskMemberItem['user_id'] > 0) {
                $currentUserId = $taskMemberItem['user_id'];
            } elseif ($taskMemberItem['partner'] > 0) {
                $currentUserId = $taskMemberItem['partner'];
            } else {
                $currentUserId = $taskMemberItem['starter'];
            }

            $taskMemberId = $taskMemberItem['id'];

            if (isset($taskMemberData[$currentUserId])) {
                //如果存在,判定是否需要修改
                $newData = ['user_id' => $taskMemberData[$currentUserId]['user_id'], 'partner' => $taskMemberData[$currentUserId]['partner'], 'starter' => $taskMemberData[$currentUserId]['starter']];
                $newDataKey = join("-", $newData);
                $oldData = ["user_id" => $taskMemberItem['user_id'], "partner" => $taskMemberItem['partner'], "starter" => $taskMemberItem['starter']];
                $oldDataKey = join("-", $oldData);


                if (isset($newTaskMemberRelationMap[$currentUserId])) {
                    $newRelationDataMap = $newTaskMemberRelationMap[$currentUserId];
                    $oldRelationData = $taskMemberRelationMap[$currentUserId] ?? [];
                    $oldRelationDataMap = [];
                    foreach ($oldRelationData as $oldRelationDataItem) {
                        $oldRelationDataMap[join("-", [$oldRelationDataItem['link_module_code'], $oldRelationDataItem['link_id'], $oldRelationDataItem['department_id']])] =
                            $oldRelationDataItem;
                    }

                    $diffNewRelationData = array_diff_key($newRelationDataMap, $oldRelationDataMap);
                    foreach ($diffNewRelationData as $diffNewRelationDataItem) {
                        //补齐task_member_id
                        $diffNewRelationDataItem['task_id'] = $taskId;
                        $diffNewRelationDataItem['task_member_id'] = $taskMemberId;
                        $taskMemberNeedAddRelationData[] = $diffNewRelationDataItem;
                    }

                    $needDeleteRelationData = array_diff_key($oldRelationDataMap, $newRelationDataMap);
                    $deleteRelationIds = array_merge($deleteRelationIds, array_column($needDeleteRelationData, 'id'));

                    unset($newTaskMemberRelationMap[$currentUserId]);
                } else { // 不存在应该删掉
                    // 应该两者同时存在,才清掉多余的关联,否则两者有一种存在,该部门都不应当被清掉
                    if (isset($data['executor_list']) && isset($data['starter_list'])) {
                        $deleteRelationIds = array_merge($deleteRelationIds, array_column($taskMemberRelationMap[$currentUserId] ?? [], 'id'));
                    }
                }

                //判定是否完全相同
                unset($taskMemberData[$currentUserId]);
                if ($newDataKey == $oldDataKey) {
                    continue;
                } else {
                    foreach ($newData as $newDataIndex => $newDataItem) {
                        if ($oldData[$newDataIndex] != $newDataItem) {
                            //如果为新值不为0或者为0且传递过
                            if (!empty($newDataItem)) {
                                $taskMemberItem[$newDataIndex] = $newDataItem;

                                if ($newDataIndex == 'user_id') {
                                    $needAddExecutor[$taskId]['add'][] = $newDataItem;
                                }

                            } else {
                                if ($isMemberDataExist[$newDataIndex]) {
                                    $taskMemberItem[$newDataIndex] = $newDataItem;

                                    if ($newDataIndex == 'user_id') {
                                        $needAddExecutor[$taskId]['delete'][] = $currentUserId;
                                    }
                                }
                            }
                        }
                    }
                    $updateTaskMemberData[] = [
                        'id' => $taskMemberItem['id'],
                        'user_id' => $taskMemberItem['user_id'],
                        'partner' => $taskMemberItem['partner'],
                        'starter' => $taskMemberItem['starter'],
                        'updated' => $currentTime,
                    ];
                }
            } else { //如果不存在

                $isUpdate = false;
                //如果是执行人,且执行人如果传了 ,则证明该执行人置空了
                if ($taskMemberItem['user_id'] > 0 && $isExecutor) {
                    $needAddExecutor[$taskId]['delete'][] = $currentUserId;
                    $taskMemberItem['user_id'] = 0;
                    $isUpdate = true;
                }

                //如果只是发起人 , 且发起人传了 ,则证明该发起人置空了
                if ($taskMemberItem['user_id'] == 0 && $taskMemberItem['partner'] > 0 && $isPartner) {
                    $taskMemberItem['partner'] = 0;
                    $isUpdate = true;
                }

                //如果只是发起人 , 且传了 ,则证明该发起人置空了
                if ($taskMemberItem['starter'] > 0 && $isStarter) {
                    $taskMemberItem['starter'] = 0;
                    $isUpdate = true;
                }

                //如果三者有一个不为空,且有更新操作
                if ((!empty($taskMemberItem['user_id']) || !empty($taskMemberItem['partner']) || !empty($taskMemberItem['starter'])) && $isUpdate) {
                    $updateTaskMemberData[] = [
                        'id' => $taskMemberItem['id'],
                        'user_id' => $taskMemberItem['user_id'],
                        'partner' => $taskMemberItem['partner'],
                        'starter' => $taskMemberItem['starter'],
                        'updated' => $currentTime,
                    ];
                }

            }

            //如果三者都空,则删除
            if (empty($taskMemberItem['user_id']) && empty($taskMemberItem['partner']) && empty($taskMemberItem['starter'])) {
                $deleteIds[$taskMemberItem['id']] = $taskMemberItem['id'];
                $deleteRelationIds = array_merge($deleteRelationIds, array_column($taskMemberRelationMap[$currentUserId] ?? [], 'id'));
            }
        }

        //剩下的将用于新增
        $newTaskMemberData = [];
        foreach ($taskMemberData as $taskMemberDataItem) {
            if ($taskMemberDataItem['user_id'] > 0) {
                $needAddExecutor[$taskId]['add'][] = $taskMemberDataItem['user_id'];
            }
            $newTaskMemberData[] = [
                'task_id' => $taskId,
                'user_id' => $taskMemberDataItem['user_id'],
                'partner' => $taskMemberDataItem['partner'],
                'starter' => $taskMemberDataItem['starter'],
                'status' => $taskStatus,
                'updated' => $currentTime,
                'created' => $currentTime,
            ];
        }

        //新增的关联
        $needAddRelationData = [];
        foreach ($newTaskMemberRelationMap as $newTaskMemberRelationList) {
            foreach ($newTaskMemberRelationList as $newTaskMemberRelationItem) {
                $newTaskMemberRelationItem['task_id'] = $taskId;
                $needAddRelationData[] = $newTaskMemberRelationItem;
            }
        }

        return [
            'need_add' => $newTaskMemberData,
            'need_update' => $updateTaskMemberData,
            'need_delete' => array_values($deleteIds),
            'need_add_relation' => $needAddRelationData,
            'task_member_need_add_relation' => $taskMemberNeedAddRelationData,
            'need_delete_relation' => array_unique($deleteRelationIds),
            'need_add_delete_executor' => $needAddExecutor,
        ];
    }

    /**
     * 获取任务成员中的所有用户id
     * @param $taskMemberList
     * @param string $type
     * @return array
     */
    public function getTaskMemberAllUserIds($taskMemberList, $type = 'user_ids')
    {
        $res = [];
        foreach ($taskMemberList as $taskMemberItem) {
            $currentUserId = 0;
            if ($type == 'user_task_member_filter') {
                if ($taskMemberItem['user_id'] > 0) {
                    $res[] = [
                        'task_id' => $taskMemberItem['task_id'],
                        'user_id' => $taskMemberItem['user_id']
                    ];
                } elseif ($taskMemberItem['partner'] > 0) {
                    $res[] = [
                        'task_id' => $taskMemberItem['task_id'],
                        'partner' => $taskMemberItem['partner']
                    ];
                } elseif ($taskMemberItem['starter'] > 0) {
                    $res[] = [
                        'task_id' => $taskMemberItem['task_id'],
                        'starter' => $taskMemberItem['starter']
                    ];
                }
            } else {
                if ($taskMemberItem['user_id'] > 0) {
                    $currentUserId = $taskMemberItem['user_id'];
                } elseif ($taskMemberItem['partner'] > 0) {
                    $currentUserId = $taskMemberItem['partner'];
                } elseif ($taskMemberItem['starter'] > 0) {
                    $currentUserId = $taskMemberItem['starter'];
                }
            }

            if ($type == 'user_ids') {
                $res[] = $currentUserId;
            } elseif ($type == 'task_user_map') {
                $res[$taskMemberItem['task_id'] . "-" . $currentUserId] = $taskMemberItem;
            }
        }

        if ($type == 'user_task_member_filter' && count($res) > 1) {
            $res["_logic"] = "OR";
            $res = [$res];
        }

        return $res;
    }


    /**
     * 获取处理的成员数据
     * @param $data
     * @param int $taskStatus
     * @return array
     * @throws \think\Exception
     */
    public function getDealTaskMemberData($data, &$taskStatus = 0)
    {
        if (!isset($data['executor']) && isset($data['partner']) && isset($data['executor_list']) && isset($data['starter_list']) && isset($data['partner_list'])) {
            return [];
        }

        if ($taskStatus == 0) {
            $statusService = StatusService::getInstance();
            $taskDefaultStatus = $statusService->getTaskDefaultStatus();
            $taskStatus = $taskDefaultStatus['id'];
        }


        //获取处理后的数据
        $taskMemberDataMerge = $this->dealTaskMemberDataMerge($data);
        $taskMemberData = $taskMemberDataMerge['task_member_data'];
        $taskMemberRelation = $taskMemberDataMerge['task_member_relation'];

        //获取更新数据
        $allocationMember = $this->getUpdateMemberData($taskMemberData, $taskMemberRelation, $data['task']['id'], $taskStatus, $data);
        //            $allocationMember = $this->allocationMember($data['task']['id'], $data['executor_list'] ?? null, $data['partner'] ?? null, $taskStatus);

        if (!empty($data['template_todo_list'])) {
            // 更新task 执行人数据
            $taskExecutorUpData = [];
            foreach ($data['template_todo_list'] as $templateTodoItem) {
                //没有Id的跳过
                if (empty($templateTodoItem['task']['id'])) {
                    continue;
                }
                // 执行人 group 转 user_list
                if (!empty($templateTodoItem['executor_list'])) {
                    foreach ($templateTodoItem['executor_list'] as &$executorListGroupItem) {
                        if (!empty($executorListGroupItem['group'])) {
                            $executorListGroupItem['user_list'] = $executorListGroupItem['group'];
                        }
                    }
                }
                $childrenTodoMember = $this->getDealTaskMemberData($templateTodoItem, $taskStatus);
                foreach ($childrenTodoMember as $childrenTodoIndex => $childrenTodoMemberItem) {
                    $allocationMember[$childrenTodoIndex] = array_merge($allocationMember[$childrenTodoIndex], $childrenTodoMemberItem);
                }
                if (!empty($templateTodoItem['executor_list'])) {
                    $taskExecutorUpData[] = [
                        'id' => $templateTodoItem['task']['id'],
                        'executor_list' => $templateTodoItem['executor_list'],
                        'plan_end_time' => $templateTodoItem['plan_end_time']
                    ];
                }
            }
            if (!empty($taskExecutorUpData)) {
                CommonService::instance('task')->commonBatchUpdate($taskExecutorUpData, module_by_code('task'), false);
            }
        }

        return $allocationMember;
    }


    /**
     * 从`task_member`表中获取指定身份 _发起人、执行人、参与人_ 的ID列表
     * Tip: This function could be \*deprecated\* when table `task_mamber` is __removed__.
     * @param string $identityToken 身份类型
     * @param array $userIdList 用户id列表
     * @return array|false|mixed
     */
    public function getTaskMemberByIdentity(string $identityToken, array $userIdList = [])
    {
        if (empty($userIdList)) {
            return [];
        }

        $fieldUserId = '';
        switch ($identityToken) {
            case 'starter':
                $fieldUserId = 'starter';
                break;
            case 'executor':
                $fieldUserId = 'user_id';
                break;
            case 'partner':
                $fieldUserId = 'partner';
                break;
            default:
                return [];
        }
        $result = model(TaskMemberModel::class)
            ->where([
                'user_id' => ['IN', $userIdList, 'user_id']
            ])
            ->field("id, ${fieldUserId} as user_id, status")
            ->select();
        return array_combine(array_column($result, 'id'), $result);
    }

    /**
     * 复制排期任务到多个剧集
     * @param int $planId
     * @param int $taskId
     * @param $episodeIdList
     * @return void
     * @throws Exception
     */
    public function copyPlanTaskToEpisodeIdList(int $planId, int $taskId, $episodeIdList)
    {
        $task = model(TaskModel::class)->find($taskId);
        $taskRelationTagList = model(TaskRelationTagModel::class)
            ->where(['task_id' => $taskId])
            ->field('id,updated', true)
            ->select();
        $taskRelationTagList = array_filter($taskRelationTagList, function ($tag) {
            return $tag['link_module_code'] <> 'episode';
        });
        $taskRelationTagList = array_values($taskRelationTagList);
        $relationTaskList = model(TaskModel::class)
            ->join("task_relation on task.id = task_relation.source_task_id")
            ->field('task.*,task_relation.relation_type')
            ->where(["task_relation.source_task_id" => $taskId])
            ->select();

        $planTaskRelationList = [];
        foreach ($episodeIdList as $episodeId) {
            $currentTask = $task;
            unset($currentTask['id']);
            $currentTask['episode_id'] = $episodeId;
            $currentTask['created'] = time();
            $currentTask['created_by'] = fill_created_by();
            $currentTaskId = model(TaskModel::class)->add($currentTask);
            $planTaskRelationList[] = [
                'plan_id' => $planId,
                'task_id' => $currentTaskId,
                'created_by' => fill_created_by(),
                'created' => time(),
            ];
            $currentTaskRelationTagList = $taskRelationTagList;
            $currentTaskRelationTagList[] = [
                'link_id' => $episodeId,
                'link_module_code' => 'episode',
            ];

            if (!empty($currentTaskRelationTagList)) {
                foreach ($currentTaskRelationTagList as &$currentTaskRelationTagItem) {
                    $currentTaskRelationTagItem['task_id'] = $currentTaskId;
                    $currentTaskRelationTagItem['project_id'] = $currentTask['project_id'];
                    $currentTaskRelationTagItem['tenant_id'] = $currentTask['tenant_id'];
                    $currentTaskRelationTagItem['created'] = time();
                    $currentTaskRelationTagItem['created_by'] = fill_created_by();
                    ksort($currentTaskRelationTagItem);
                }
            }
            model(TaskRelationTagModel::class)->addAll($currentTaskRelationTagList);
            // 关联任务
            $currentDownstreamTaskList = [];
            $currentDownstreamTaskRelationList = [];
            foreach ($relationTaskList as $relationTaskItem) {
                $relationType = $relationTaskItem['relation_type'];
                unset($relationTaskItem['id'], $relationTaskItem['relation_type']);
                $relationTaskList[] = $relationTaskItem;
                $currentDownstreamTaskId = model(TaskModel::class)->add($relationTaskItem);
                $currentDownstreamTaskRelationList[] = [
                    'source_task_id' => $currentTaskId,
                    'target_task_id' => $currentDownstreamTaskId,
                    'relation_type' => $relationType,
                    'uuid' => create_uuid(),
                ];
            }
            if (!empty($currentDownstreamTaskRelationList)) {
                $projectId = $task['project_id'] ?? 0;
                model(TaskRelationModel::class)->setSuffix(sprintf('_project_%d', $projectId))->addAll($currentDownstreamTaskRelationList);
            }
        }

        if (!empty($planTaskRelationList)) {
            model(PlanTaskRelationModel::class)->addAll($planTaskRelationList);
        }
    }


    /**
     * 兼容处理模板代办group参数
     * @param $list
     * @return array|mixed
     * @throws \think\Exception
     */
    public function execGroupUserList($list)
    {
        if (!empty($list['group'])) {
            return $list;
        }
        $unionIds = [];
        $roles = [];
        $departmentIds = [];
        foreach ($list as $item) {
            if ($item['type'] == 'role') {
                $roles[] = $item['id'][0];
            }
            foreach ($item['user_list'] ?? [] as $userItem) {
                if (!empty($userItem['user_id'])) {
                    $unionIds[] = $userItem['user_id'];
                }
                if (!empty($userItem['department_id'])) {
                    $departmentIds[] = $userItem['department_id'];
                }
            }
        }
        $unionIds = join(',', array_unique($unionIds));
        $roles = join(',', array_unique($roles));
        $departmentIds = join(',', array_unique($departmentIds));
        $userList = model(UserModel::class)->where(['union_id' => ['IN', $unionIds]])->field('')->select();
        $userMap = array_column($userList, null, 'union_id');
        $roleInfo = teamones_request('teamones-im', 'role/select', ["param" => [
            "filter" => [
                "role.id" => ['-in', $roles]
            ],
            "fields" => "role.id,role.name,role.code"
        ]]);
        $roleNameMap = [];
        if (!empty($roleInfo['data']['rows'])) {
            $roleNameMap = array_column($roleInfo['data']['rows'], null, 'id');
        }
        $departmentList = teamones_request('teamones-im', 'department/select', [
            'param' => [
                'filter' => [
                    'id' => ['-in', $departmentIds],
                ],
                'fields' => 'id,name'
            ]
        ]);
        $departmentMap = [];
        if (!empty($departmentList['data']['rows'])) {
            $departmentMap = array_column($departmentList['data']['rows'], null, 'id');
        }

        $producerStepCategoryMap = [];
        $producerStepCategoryList = ProjectService::getInstance()->getShowStepCategoryList('');
        foreach ($producerStepCategoryList as $item) {
            $producerStepCategoryMap[$item['show_name']][] = ['show_name' => $item['show_name'], 'id' => $item['id'], 'code' => $item['code']];
        }

        return array_map(function ($tmp) use ($userMap, $roleNameMap, $departmentMap, $producerStepCategoryMap) {
            $group = [];
            foreach ($tmp['user_list'] ?? [] as $userItem) {
                $group[] = [
                    'children_ids' => $tmp['id'],
                    'department_id' => intval($userItem['department_id']),
                    'user_id' => intval($userItem['user_id']),
                    'user_list' => [
                        ['department_id' => intval($userItem['department_id']), 'user_name' => $userMap[$userItem['user_id']]['name'], 'user_id' => intval($userItem['user_id']), 'department_name' => $departmentMap[$userItem['department_id']]['name']]
                    ]
                ];
            }
            switch ($tmp['type']) {
                case 'role':
                    $roleIdx = $tmp['id'][0] ?? 0;
                    $name = $roleNameMap[$roleIdx]['name'] ?? '';
                    break;
                case 'step_category':
                    $producerStepCategoryMapList = TemplateTodoService::getInstance()->stepCategoryShowNameGroupList($tmp['id'], $producerStepCategoryMap);
                    $name = array_keys($producerStepCategoryMapList)[0] ?? '';
                    break;
            }
            $tmp['group'] = $group;
            $tmp['name'] = $name ?? '';
            $tmp['children_ids'] = $tmp['id'];
            return $tmp;
        }, $list);
    }

    /**
     * 为交付列表关联[最新版本/指定版本]上传状态
     * @param $deliveryList
     * @param $versionId
     * @param $taskId
     * @param $versionNum
     * @return mixed
     */
    public function getDeliveryCurrent($deliveryList, $versionId, $taskId = null, $versionNum = null)
    {
        $filter = [];
        $res = [
            'number' => 0,
            'created' => 0,
            'delivery_list' => $deliveryList
        ];

        if (empty($deliveryList)) {
            return $res;
        }

        if (!empty($versionId)) {
            $filter['id'] = $versionId;
        } else if (!empty($taskId)) {
            $filter['link_id'] = $taskId;
            if (!empty($versionNum)) {
                $filter['number'] = $versionNum;
            }
        } else {
            return $res;
        }

        $filter['module_id'] = module_by_code('task')['id'];
        $mediaVersion = model(VersionModel::class)
            ->where($filter)
            ->field("json_unquote(json_extract(json,'$.version_cos_media')) as version_cos_media, number, created")
            ->order('number desc')
            ->find();

        if (empty($mediaVersion)) {
            return $res;
        }

        $mediaIdList = explode(',', $mediaVersion['version_cos_media'] ?? '');
        $mediaList = [];
        if (!empty($mediaIdList)) {
            $mediaList = model(CosMediaModel::class)
                ->where(['id' => ['IN', $mediaIdList]])
                ->field("json_unquote(json_extract(param,'$.delivery_id')) as delivery_id, file_name, object, cos_key, param, request_url")
                ->select();
            $mediaList = array_combine(array_column($mediaList, 'delivery_id'), $mediaList);
        }

        foreach ($deliveryList as &$item) {
            $item['cos_media'] = $mediaList[$item['id']] ?? [];
            $item['cos_media']['param'] = json_decode($item['cos_media']['param'] ?? '', true);
            unset($item['cos_media']['delivery_id']);
        }

        $res['number'] = $mediaVersion['number'];
        $res['created'] = $mediaVersion['created'];
        $res['delivery_list'] = $deliveryList;
        return $res;
    }

    /**
     * 根据任务ID和交付文件类型ID查找版本历史
     * @param $param
     * @return array|false|mixed|string
     */
    public function getDeliveryVersionHistory($filter, $page)
    {
        $deliveryId = $filter['delivery_id'] ?? 0;
        if (empty($deliveryId)) {
            return [];
        }
        unset($filter['delivery_id']);

        $versionList = model(VersionModel::class)
            ->where($filter)
            ->page($page[0], $page[1])
            ->field("id, number, link_id as task_id, json_unquote(json_extract(json,'$.version_cos_media')) as version_cos_media, number, created")
            ->order('number desc')
            ->select();
        $versionMediaList = explode(',', implode(',', array_column($versionList, 'version_cos_media')));

        $cosMediaList = model(CosMediaModel::class)
            ->where(['id' => ['IN', $versionMediaList]])
            ->field("id, file_name, object, cos_key, param, request_url")
            ->select();
        $cosMediaList = array_combine(array_column($cosMediaList, 'id'), $cosMediaList);

        foreach ($cosMediaList as &$item) {
            unset($item['id']);
            $item['param'] = json_decode($item['param'], true);
        }

        $res = [];
        foreach ($versionList as $versionRow) {
            $versionMedia = explode(',', $versionRow['version_cos_media']);
            foreach ($versionMedia as $mediaId) {
                if (isset($cosMediaList[$mediaId]) && ($cosMediaList[$mediaId]['param']['delivery_id'] == $deliveryId)) {
                    $res[] = [
                        'version' => $versionRow['number'],
                        'created' => $versionRow['created'],
                        'cos_media' => $cosMediaList[$mediaId]
                    ];
                }
            }
        }
        return $res;
    }


    /**
     * 添加工单成员
     * @param $data
     * @return array
     * @throws \Throwable
     */
    public function addWorkOrderUser($data)
    {
        $res = [];
        $userIdList = array_column($data['user_list'], 'id');
        $userIdMap = $this->getSaasUserId($userIdList, true);
        $workOrderData = model(TaskWorkOrderModel::class)->find($data['work_order_id']);
        $taskWorkOrderUserList = model(TaskWorkOrderUserModel::class)->where(['work_order_id' => $data['work_order_id']])->select();
        $taskWorkOrderUserList = array_column($taskWorkOrderUserList, null, 'user_id');
        $projectMemberDataUserList = [

        ];
        $add = [];
        $created = time();
        $addUserIds = [];

        foreach ($data['user_list'] as $user) {
            $currentUserId = $userIdMap[$user['id']] ?? 0;
            if ($currentUserId === 0) {
                continue;
            }
            // 新加入的成员  添加到项目成员中去
            if (!empty($user['role_code'])) {
                $projectMemberDataUserList[] = [
                    'user_id' => $currentUserId,
                    'role_code' => $user['role_code'],
                ];
            }

            // 判断成员的添加
            if (!isset($taskWorkOrderUserList[$currentUserId])) {
                $add[] = [
                    'user_id' => $currentUserId,
                    'work_order_id' => $data['work_order_id'],
                    'created' => $created,
                ];
                $addUserIds[] = $user['id'];
            }
        }
        $addedHookData = [
            'add' => $add,
            'work_order_id' => $data['work_order_id'],
            'join_type' => 'invite',
        ];


        $receiverUnionIds = [];
        $taskData = [];

        if (empty($workOrderData['chat_global_id']) && !empty($addUserIds)) {
            $createdBy = model(UserModel::class)->field("id,union_id")->find($workOrderData['created_by']);
            array_unshift($addUserIds, $createdBy['union_id']);
            $receiverUnionIds = array_unique($addUserIds);
            $taskData = model(TaskModel::class)->field("id,name")->find($workOrderData['task_id']);
        }

        model(TaskWorkOrderUserModel::class)->startTrans();
        try {
            //没有群聊需要创建群聊
            if (!empty($add)) {
                $res[] = model(TaskWorkOrderUserModel::class)->addAll($add);
            }
            if (empty($workOrderData['chat_global_id'])) {
                if (!empty($receiverUnionIds)) {
                    TaskWorkOrderService::getInstance()->addTaskWorkOrderChat($receiverUnionIds, $workOrderData, $taskData);
                }
            } else {
                if (!empty($add)) {
                    Hook::listen('task_work_order_user_added', $addedHookData);
                }
            }
            if (!empty($projectMemberDataUserList)) {
                $res[] = ProjectService::getInstance()->batchCreateProjectMemberV2($workOrderData['project_id'], ProjectMemberModel::PRODUCTION_TYPE, $projectMemberDataUserList);
            }
            model(TaskWorkOrderUserModel::class)->commit();
        } catch (Throwable $e) {
            model(TaskWorkOrderUserModel::class)->rollback();
            throw $e;
        }
        return $res;
    }

    /**
     * 删除工单成员
     * @param $data
     * @return array
     */
    public function deleteWorkOrderUser($data)
    {
        $res = [];
        $userIdList = array_column($data['user_list'], 'id');
        $userIdMap = $this->getSaasUserId($userIdList, true);
        $taskWorkOrderUserList = model(TaskWorkOrderUserModel::class)->where(['work_order_id' => $data['work_order_id']])->select();
        $taskWorkOrderUserList = array_column($taskWorkOrderUserList, null, 'user_id');

        $deleteTaskWorkUserList = [];
        foreach ($data['user_list'] as $user) {
            $currentUserId = $userIdMap[$user['id']] ?? 0;
            if ($currentUserId === 0) {
                continue;
            }

            // 判断成员的去留
            if (isset($taskWorkOrderUserList[$currentUserId])) {
                $deleteTaskWorkUserData = $taskWorkOrderUserList[$currentUserId];
                $deleteTaskWorkUserList[] = $deleteTaskWorkUserData;
            }
        }

        $del = array_column($deleteTaskWorkUserList, 'id');
        $deletedHookData = [
            'del' => array_column($deleteTaskWorkUserList, 'user_id'),
            'work_order_id' => $data['work_order_id']
        ];
        if (!empty($del)) {
            $res = model(TaskWorkOrderUserModel::class)->where(['id' => ['IN', $del]])->delete();
            Hook::listen('task_work_order_user_deleted', $deletedHookData);
        }
        return $res;
    }

}
